自訂View之大風車系列demo(一),大風車demo
每次寫部落格最討厭寫部落格的開頭,不知道該寫些什麼,現在也是,感覺跟寫八百字作文似的。之所以會寫這一系列的demo是因為前天看網上的一個圖片轉圈的源碼的時候
突發奇想要不要自己也弄個耍耍,順便學習下view的相關知識!說幹就幹,當然自己寫的時候也不免參照寫別人得到代碼,畢竟自訂view與我的水平來說確實具有挑戰性,通過完成這一些列的小demo確實收穫頗多,雖然還有些許在我看來更牛逼的功能自己沒法實現,但自己的目的也算達到了。先囉嗦了這麼多,先說說大風車系列小demo的總體概況:一共五個版本,這也意味著此系列一共會寫四到五個簡短的小部落格,每個版本都是對上一個版本的修改或者功能的改進。特註:這是個代碼很少的demo,不過對於初學者來說確實能學到點東西,所以拿來分享,如果有大神看到這些沒什麼水平的部落格希望能留下自己對android相關知識的些許評價或者批評。總之歡迎批評指正吧,閑言少敘,進入主題:
大風車版本1.0)實現功能和思慮如下:
1)風車圖片隨著手指的轉動而轉動,轉動的速度固定
2)圖片的轉動肯定設計到了androidview的重繪過程,所以postInvalidate和invalidate兩個方法準備起來。
3)既然圖片隨著手指的移動而轉動,那麼肯定會在onTouchEvent對MotionEvent.action_move事件進行補貨然後處理
4)所需要的風車圖片素材如下:
5)風車的圖片寬和高一樣,是個正方形的圖片,需要計算出來該方正行的中心,以此中心為旋轉軸進行旋轉。
通過上面五個說明得出自訂的View代碼如下:
package rotation.demo.view;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Matrix;import android.graphics.Paint;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;/** * verson 1.0 * 隨手指轉動而轉動的風車 * 轉動的思路 * 1)風車轉動的涉及到了圖片的重繪過程 * 2)監聽手指的move事件,當move事件被監聽到的時候調用相關方法來進行重繪 * 3)用矩陣變換來實現風車的轉動 * @author xiaobenxiong * */public class RotationView extends View{/**要轉動的圖片**/private Bitmap bitMap;/**風車每次轉動的弧度**/private int rad = 30;/**圖片的寬度:在這裡提供的是正方形的圖片,所以寬度和高度是一樣的**/private int width = 0;/***圖片的高度:在這裡提供的是正方形的圖片,所以寬度和高度是一樣的**/private int height = 0;/**定義一個畫筆**/private Paint paint = new Paint();public RotationView(Context context, AttributeSet attrs) {super(context, attrs);}public RotationView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}public RotationView(Context context) {super(context);}/** * 擷取圖片的寬和高 */public void initSize() { width = bitMap.getWidth(); height = bitMap.getHeight(); postInvalidate();}public void setBitMap(Bitmap bitMap) {this.bitMap = bitMap;} //一圖片的寬和高來設定自訂View的寬和高,由於是正方形寬和高是一樣的@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// TODO Auto-generated method stubsuper.onMeasure(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(width, width);} /*** *實現onDraw方法把風車圖片繪製出來,同時繪製出來風車的旋轉效果,通過Matrix來控制 */ @Override protected void onDraw(Canvas canvas) { Matrix matrix = new Matrix(); // 設定轉軸位置 matrix.setTranslate((float)width / 2, (float)height / 2); rad -=3;//每次旋轉的弧度增量為3當然,數字越大轉動越快 // 開始轉 matrix.preRotate(rad); // 轉軸還原 matrix.preTranslate(-(float)width / 2, -(float)height / 2); //繪製風車圖片 canvas.drawBitmap(bitMap, matrix,paint); super.onDraw(canvas); }@Overridepublic boolean onTouchEvent(MotionEvent event) {int action = event.getAction();switch (action) {case MotionEvent.ACTION_MOVE://隨著手指的move而不斷進行重繪,進而讓風車轉動起來 postInvalidate();//調用方法進行重繪break;}return true;} }
上面的代碼很簡單,主要對MotionEvent.ACTION_MOVE事件進行捕獲,並調用postInvalidate方法來實現重繪,在onDraw方法中通過Martix的變化來實現風車的旋轉效果。在這裡要注意:
1)onTouchEvent要返回true否則不會進行執行你在這個方法裡面寫的程式,具體原因見android事件攔截機制
在設定檔裡面使用如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffffffff" > <rotation.demo.view.RotationView android:id="@+id/rotationView" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_centerInParent="true"> </rotation.demo.view.RotationView ></RelativeLayout>
public class MainActivity extends Activity { @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);RotationView rotation = (RotationView)findViewById(R.id.rotationView);BitmapDrawable drawable = (BitmapDrawable) getResources().getDrawable(R.drawable.fengche);rotation.setBitMap(drawable.getBitmap());rotation.initSize();}}
經過運行會發現有個問題:不論是手指是順時針還是逆時針風車運動的方向總是逆時針,經過測試發現當matrix.preRotate中的三處逐步變大的時候
就是順時針轉動,如果主鍵變小的話就是逆時針,所以我簡單的添加了個兩個按鈕來選擇是否是逆時針順時針,當逆時針的時候讓rad變數遞減,順時針遞增就可以了。為此在RotationView裡面增加了clockWise這個布爾變數,通過點擊兩個按鈕的變數改變clockWise的值。如下:
onDraw方法的代碼改動如下:
private boolean clockWise = false;@Overrideprotected void onDraw(Canvas canvas) {Matrix matrix = new Matrix();// 設定轉軸位置matrix.setTranslate((float) width / 2, (float) height / 2);if(clockWise) {//如果是順時針rad+= 30;}else { rad-= 30;}// 開始轉matrix.preRotate(degree);// 轉軸還原matrix.preTranslate(-(float) width / 2, -(float) height / 2);// 將位置送到view的中心// matrix.postTranslate((float)(width) / 2, (float)(height) / 2);canvas.drawBitmap(bitMap, matrix, paint);super.onDraw(canvas);}
經過簡單的修改,版本2就這麼誕生了,當然版本2.0還有些問題,留給版本3解決,詳見自訂View之大風車系列demo(2)