編輯:關於Android編程
首先上效果圖
第一張圖是進入該界面的效果,頂部是一個viewpager,下面每個塊都是自定義的view HomeButton,第二張圖是點擊右邊第一個方塊的效果,點擊時方塊整體有收縮的效果,中間會顯示手印,手指抬起時又恢復原樣。
在之前的一篇文章已經詳細介紹了view的繪制流程,這裡不多說,除了知道view的繪制流程外,我們還應該落實到實處,要做好自定義view當然要熟悉drawable和canvas,多在這兩塊下功夫,然後可能需要加上一些小技巧,本文的例子主要是用canvas和matrix加上動畫做的效果,這裡貼一下關於Matrix的介紹。
Matrix的對圖像的處理可分為四類基本變換:
Translate 平移變換
Rotate 旋轉變換
Scale 縮放變換
Skew 錯切變換
除平移變換(Translate)外,旋轉變換(Rotate)、縮放變換(Scale)和錯切變換(Skew)都可以圍繞一個中心點來進行,如果不指定,在默認情況下是圍繞(0, 0)來進行相應的變換的。
針對每種變換,Android提供了pre、set和post三種操作方式。其中
set用於設置Matrix中的矩陣值。
pre是先乘,post是後乘,因為矩陣的乘法不滿足交換律,因此先乘、後乘必須要嚴格區分。先乘相當於矩陣運算中的右乘。後乘相當於矩陣運算中的左乘。
事實上,圖像處理時,矩陣的運算是從右邊往左邊方向進行運算的。這就形成了越在右邊的矩陣(右乘),越先運算(先乘),反之亦然。
post是後乘,當前的矩陣乘以參數給出的矩陣。可以連續多次使用post,來進行多種變換。例如,需要將圖片旋轉60度,然後平移到(100,,100)的地方,那麼可以這樣做:
Matrix m = new Matrix(); m.postRotate(60); m.postTranslate(100,100);
這樣就達到了效果。
pre是前乘,參數給出的矩陣乘以當前的矩陣。上面的例子,如果使用pre的話就要這樣做:
Matrix m = new Matrix(); m.setTranslate(100,100); m.preRotate(60);
HomeButton類,自定義view繼承ImageView
package com.chm.test.view; import android.app.Activity; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.animation.Animation; import android.view.animation.ScaleAnimation; import android.widget.ImageView; import com.chm.test.R; import com.chm.test.myInterface.HomeClickListener; import com.chm.test.utils.BitmapUtils; public class HomeButton extends ImageView { private Bitmap bitmap; private Bitmap home_flight; private Bitmap label_new; private int state = 0; //是否按下 private int color; private float textsize; private boolean big; private int home; private String text; private int screenW; private int screenH; //點擊事件 private HomeClickListener listener = null; private int[] colors = {getResources().getColor(R.color.red), getResources().getColor(R.color.orange), getResources().getColor(R.color.blue), getResources().getColor(R.color.purple), getResources().getColor(R.color.air), getResources().getColor(R.color.texi), getResources().getColor(R.color.jingdian)}; private Bitmap[] bitmaps = { BitmapFactory.decodeResource(getResources(), R.drawable.home_hotel), BitmapFactory.decodeResource(getResources(), R.drawable.home_groupbuy), BitmapFactory.decodeResource(getResources(), R.drawable.home_train), BitmapFactory.decodeResource(getResources(), R.drawable.home_lastmin), BitmapFactory .decodeResource(getResources(), R.drawable.home_flight), BitmapFactory.decodeResource(getResources(), R.drawable.home_car), BitmapFactory.decodeResource(getResources(), R.drawable.home_scenery) }; public HomeButton(Context context) { super(context); } public HomeButton(Context context, AttributeSet attrs) { super(context, attrs); bitmap = BitmapUtils.zoomImage(BitmapFactory.decodeResource( getResources(), R.drawable.fingerprint), 127, 122); label_new = BitmapFactory.decodeResource(getResources(), R.drawable.label_new); TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.HomeButton); color = typedArray.getInt(R.styleable.HomeButton_backcolor, 0); textsize = typedArray.getDimension(R.styleable.HomeButton_textSize, 24); big = typedArray.getBoolean(R.styleable.HomeButton_big, true); home = typedArray.getInt(R.styleable.HomeButton_home, 0); text = typedArray.getString(R.styleable.HomeButton_text); System.out.println("color:" + color + " textsize:" + textsize + " big:" + big + " home:" + home); home_flight = bitmaps[home]; screenW = ((Activity) context).getWindow().getWindowManager() .getDefaultDisplay().getWidth() / 2 - 16; if (big) { screenH = screenW; } else { screenH = screenW / 2 - 4; } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 重新設置View大小 setMeasuredDimension(screenW, screenH); } /* * orange 2182F7 light red 7359EF 紫 B551A5 Blue CE8A39 air CEBE00 texi * 9CAA00 jingdian 00AA73 */ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(colors[color]); Paint paint = new Paint(); paint.setColor(Color.WHITE); paint.setTextSize(24); if (big) { Matrix matrix = new Matrix(); matrix.postTranslate(this.getWidth() / 2 - home_flight.getWidth() / 2, this.getHeight() / 2 - home_flight.getHeight() / 2); canvas.drawText(text, 10, 40, paint); canvas.drawBitmap(home_flight, matrix, paint); } else { Matrix matrix_small = new Matrix(); matrix_small.postTranslate(10, this.getHeight() / 2 - home_flight.getHeight() / 2); canvas.drawBitmap(home_flight, matrix_small, new Paint()); if (home == 3) { paint.setTextSize(16); canvas.drawText("夜宵酒店", home_flight.getWidth() + 20, this.getHeight() / 2 - home_flight.getHeight() / 2 + 10, paint); canvas.drawText("加載中...", home_flight.getWidth() + 20, this.getHeight() / 2 + home_flight.getHeight() / 2, paint); } else if (home == 5) { paint.setTextSize(16); canvas.drawText("送機", home_flight.getWidth() + 20, this.getHeight() / 2 - home_flight.getHeight() / 2 + 10, paint); canvas.drawText("免費叫出租", home_flight.getWidth() + 20, this.getHeight() / 2 + home_flight.getHeight() / 2, paint); } else { canvas.drawText(text, home_flight.getWidth() + 20, this.getHeight() / 2 + home_flight.getHeight() / 2, paint); } if (home == 6) { Matrix matrix_new = new Matrix(); matrix_new.postTranslate(screenW - label_new.getWidth(), 0); canvas.drawBitmap(label_new, matrix_new, new Paint()); } } //按下 if (state == 1) { Matrix matrix2 = new Matrix(); matrix2.postTranslate(this.getWidth() / 2 - bitmap.getWidth() / 2, this.getHeight() / 2 - bitmap.getHeight() / 2); canvas.drawBitmap(bitmap, matrix2, new Paint()); } } @Override public boolean onTouchEvent(MotionEvent event) { float start = 1.0f; float end = 0.95f; Animation scaleAnimation = new ScaleAnimation(start, end, start, end, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); Animation endAnimation = new ScaleAnimation(end, start, end, start, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); scaleAnimation.setDuration(200); scaleAnimation.setFillAfter(true); endAnimation.setDuration(200); endAnimation.setFillAfter(true); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: this.startAnimation(scaleAnimation); state = 1; invalidate(); break; case MotionEvent.ACTION_UP: this.startAnimation(endAnimation); state = 0; invalidate(); if (listener != null) { listener.onclick(); } break; // 滑動出去不會調用action_up,調用action_cancel case MotionEvent.ACTION_CANCEL: this.startAnimation(endAnimation); state = 0; invalidate(); break; } // 不返回true,Action_up就響應不了 return true; } /** * 加入響應事件 * * @param clickListener */ public void setOnHomeClick(HomeClickListener clickListener) { this.listener = clickListener; } }
HomeClickListener接口
public interface HomeClickListener { public void onclick(); }
HotelActivity類
package com.chm.test; import android.content.Intent; import android.graphics.BitmapFactory; import android.os.Bundle; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RelativeLayout; import com.chm.mylibrary.BaseActivity; import com.chm.test.adapter.ViewPagerAdapter; import com.chm.test.myInterface.HomeClickListener; import com.chm.test.utils.BitmapUtils; import com.chm.test.view.HomeButton; import java.util.ArrayList; import java.util.List; public class HotelActivity extends BaseActivity implements View.OnClickListener,ViewPager.OnPageChangeListener { private ViewPager vp; private ViewPagerAdapter vpAdapter; private Listviews; private int width; private int height; private RelativeLayout relativeLayout; // 引導圖片資源 private static final int[] pics = { R.drawable.home1, R.drawable.home2, R.drawable.home3, R.drawable.home4 }; // 底部小店圖片 private ImageView[] dots; // 記錄當前選中位置 private int currentIndex; private View view; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.index); HomeButton button = (HomeButton) findViewById(R.id.hotel); button.setOnHomeClick(new HomeClickListener() { @Override public void onclick() { Intent intent =new Intent(); intent.setClass(HotelActivity.this, HotelActivity.class); startActivity(intent); } }); //等到屏幕的大小 width = this.getWindowManager().getDefaultDisplay().getWidth(); //以670*240的圖片為例,正常中不要這樣用 height =width*240/670; relativeLayout =(RelativeLayout) findViewById(R.id.relative); LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) relativeLayout.getLayoutParams(); layoutParams.width =width; layoutParams.height =height; relativeLayout.setLayoutParams(layoutParams); views = new ArrayList (); LinearLayout.LayoutParams mParams = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); // 初始化引導圖片列表 for (int i = 0; i < pics.length; i++) { ImageView iv = new ImageView(this); iv.setLayoutParams(mParams); //改變大小 // iv.setImageResource(pics[i]); iv.setImageBitmap(BitmapUtils.zoomImage(BitmapFactory.decodeResource(getResources(), pics[i]), width, height)); views.add(iv); } vp = (ViewPager) findViewById(R.id.viewpager); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(width, height); params.leftMargin=10; params.topMargin=10; params.rightMargin=10; vp.setLayoutParams(params); // 初始化Adapter vpAdapter = new ViewPagerAdapter(views); vp.setAdapter(vpAdapter); // 綁定回調 vp.setOnPageChangeListener(this); // 初始化底部小點 initDots(); } private void initDots() { LinearLayout ll = (LinearLayout) findViewById(R.id.ll); dots = new ImageView[pics.length]; // 循環取得小點圖片 for (int i = 0; i < pics.length; i++) { dots[i] = (ImageView) ll.getChildAt(i); dots[i].setEnabled(true);// 都設為灰色 dots[i].setOnClickListener(this); dots[i].setTag(i);// 設置位置tag,方便取出與當前位置對應 } currentIndex = 0; dots[currentIndex].setEnabled(false);// 設置為白色,即選中狀態 } /** * 設置當前的引導頁 */ private void setCurView(int position) { if (position < 0 || position >= pics.length) { return; } vp.setCurrentItem(position); } /** * 這只當前引導小點的選中 */ private void setCurDot(int positon) { if (positon < 0 || positon > pics.length - 1 || currentIndex == positon) { return; } dots[positon].setEnabled(false); dots[currentIndex].setEnabled(true); currentIndex = positon; } // 當滑動狀態改變時調用 @Override public void onPageScrollStateChanged(int arg0) { } // 當當前頁面被滑動時調用 @Override public void onPageScrolled(int arg0, float arg1, int arg2) { vp.requestDisallowInterceptTouchEvent(true); } // 當新的頁面被選中時調用 @Override public void onPageSelected(int arg0) { // 設置底部小點選中狀態 setCurDot(arg0); } @Override public void onClick(View view) { int position = (Integer) view.getTag(); setCurView(position); setCurDot(position); } }
布局文件index.xml
本節引言: 本章節是Android基礎入門教程的最後一章,主要講解是一些零零散散的一些知識點,以及一些遺漏 知識點的補充,這些零散的知識點包括,各
DefaultItemAnimator是Android OS中一個默認的RecyclerView動畫實現類,如果產品需求沒有特別復雜的動畫要求,可以使用DefaultIt
前言博主由於項目中頻繁的使用了V7包中的RecyclerView來代替ListView的列表展示,所以抽空基於ListView的通用適配器的原理,給RecyclerVie
微信開放平台和公眾平台的區別1.公眾平台面向的時普通的用戶,比如自媒體和媒體,企業官方微信公眾賬號運營人員使用,當然你所在的團隊或者公司有實力去開發一些內容,也可以調用公