編輯:關於Android編程
基於View類實現自定義View –MyImageView類。在使用View的Activity類中完成OnTouchListener接口,實現對MotionEvent事件的監聽與處理,常見的MotionEvent事件如下:
ACTION_DOWN事件,記錄平移開始點
ACTION_UP事件,結束平移事件處理
ACTION_MOVE事件,記錄平移點,計算與開始點距離,實現Bitmap平移,在多點觸控時候,計算兩點之間的距離,實現圖像放大
ACTION_POINTER_DOWN事件,計算兩點之間的距離,作為初始距離,實現圖像手勢放大時候使用。
ACTION_POINTER_UP事件,結束兩點觸控放大圖像處理
setMovePoint()設置圖像平移的移動點坐標,然後集合開始點位置,計算它們之間的距離,從而得到Bitmap對象需要平移的兩個參數值sx、sy。其中還包括保證圖像不會越過View邊界的檢查代碼。
savePreviousResult()保存當前的平移數據,下次可以繼續在次基礎上平移Bitmap對象。
zoomIn()根據兩個點之間的歐幾裡德距離,通過初始距離比較,得到放大比例,實現Bitmap在View對象上的放大
Matrix中關於放大與平移的API
Matrix.postScale方法與Matrix.postTranslate方法可以不改變Bitmap對象本身實現平移與放大。
二:代碼實現
自定義View類使用xml布局如下:
自定義View實現代碼如下:
package com.example.matrixdemo; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Point; import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; public class MyImageView extends View { private Paint mPaint; private Bitmap bitmap; private Matrix matrix; // 平移開始點與移動點 private Point startPoint; private Point movePoint; private float initDistance; // 記錄當前平移距離 private int sx; private int sy; // 保存平移狀態 private int oldsx; private int oldsy; // scale rate private float widthRate; private float heightRate; public MyImageView(Context context) { super(context); } public MyImageView(Context context, AttributeSet attrs) { super(context, attrs); } public void setBitmap(Bitmap bitmap) { this.bitmap = bitmap; } private void initParameters() { // 初始化畫筆 mPaint = new Paint(); mPaint.setColor(Color.BLACK); matrix = new Matrix(); if(bitmap != null) { float iw = bitmap.getWidth(); float ih = bitmap.getHeight(); float width = this.getWidth(); float height = this.getHeight(); // 初始放縮比率 widthRate = width / iw; heightRate = height / ih; } sx = 0; sy = 0; oldsx = 0; oldsy = 0; } public void setStartPoint(Point startPoint) { this.startPoint = startPoint; } public void setInitDistance(float initDistance) { this.initDistance = initDistance; } public void zoomIn(float distance) { float rate = distance / this.initDistance; float iw = bitmap.getWidth(); float ih = bitmap.getHeight(); float width = this.getWidth(); float height = this.getHeight(); // get scale rate widthRate = (width / iw ) * rate; heightRate = (height / ih) * rate; // make it same as view size float iwr = (width / iw ); float ihr = (height / ih); if(iwr >= widthRate) { widthRate = (width / iw ); } if(ihr >= heightRate) { heightRate = (height / ih); } // go to center oldsx = (int)((width - widthRate * iw) / 2); oldsy = (int)((height - heightRate * ih) / 2); } public void setMovePoint(Point movePoint) { this.movePoint = movePoint; sx = this.movePoint.x - this.startPoint.x; sy = this.movePoint.y - this.startPoint.y; float iw = bitmap.getWidth(); float ih = bitmap.getHeight(); // 檢測邊緣 int deltax = (int)((widthRate * iw) - this.getWidth()); int deltay = (int)((heightRate * ih) - this.getHeight()); if((sx + this.oldsx) >= 0) { this.oldsx = 0; sx = 0; } else if((sx + this.oldsx) <= -deltax) { this.oldsx = -deltax; sx = 0; } if((sy + this.oldsy) >= 0) { this.oldsy = 0; this.sy = 0; } else if((sy + this.oldsy) <= -deltay) { this.oldsy = -deltay; this.sy = 0; } float width = this.getWidth(); // 初始放縮比率 float iwr = width / iw; if(iwr == widthRate) { sx = 0; sy = 0; oldsx = 0; oldsy = 0; } } public void savePreviousResult() { this.oldsx = this.sx + this.oldsx; this.oldsy = this.sy + this.oldsy; // zero sx = 0; sy = 0; } @Override protected void onDraw(Canvas canvas) { if(matrix == null) { initParameters(); } if(bitmap != null) { matrix.reset(); matrix.postScale(widthRate, heightRate); matrix.postTranslate(oldsx+sx, oldsy + sy); canvas.drawBitmap(bitmap, matrix, mPaint); } else { // fill rect Rect rect = new Rect(0, 0, getWidth(), getHeight()); mPaint.setAntiAlias(true); mPaint.setColor(Color.BLACK); mPaint.setStyle(Style.FILL_AND_STROKE); canvas.drawRect(rect, mPaint); } } }Activity類中實現對View的OnTouchListener監聽與MotionEvent事件處理的代碼如下:
package com.example.matrixdemo; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Point; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; public class MainActivity extends Activity implements OnTouchListener { public static final int SCALE_MODE = 4; public static final int TRANSLATION_MODE = 2; public static final int NULL_MODE = 1; private MyImageView myView; private int mode; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); startMyImageView(); } private void startMyImageView() { myView = (MyImageView) this.findViewById(R.id.myView); Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.flower_001); myView.setBitmap(bitmap); myView.setOnTouchListener(this); myView.invalidate(); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onTouch(View view, MotionEvent event) { Log.i(touch event,touch x = + event.getX()); switch (MotionEvent.ACTION_MASK & event.getAction()) { case MotionEvent.ACTION_DOWN: mode = TRANSLATION_MODE; myView.setStartPoint(new Point((int)event.getX(), (int)event.getY())); break; case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_OUTSIDE: case MotionEvent.ACTION_UP: mode = NULL_MODE; myView.savePreviousResult(); break; case MotionEvent.ACTION_POINTER_DOWN: mode = SCALE_MODE; myView.setInitDistance(calculateDistance(event)); break; case MotionEvent.ACTION_MOVE: if(mode == SCALE_MODE) { float dis = calculateDistance(event); myView.zoomIn(dis); } else if(mode == TRANSLATION_MODE) { myView.setMovePoint(new Point((int)event.getX(), (int)event.getY())); } else { Log.i(unknow mode tag,do nothing......); } break; } myView.invalidate(); return true; } private float calculateDistance(MotionEvent event) { float dx = event.getX(0) - event.getX(1); float dy = event.getY(0) - event.getY(1); float distance = (float)Math.sqrt(dx*dx + dy*dy); return distance; } }三:運行效果如下
在這裡,總結一下loading進度條的使用簡單總結一下。一、說起進度條,必須說說條形進度條,經常都會使用到嘛,特別是下載文件進度等等,還有像騰訊QQ安裝進度條一樣,有個進
使用場景在開發中,或許一個業務需求中會出現很多系統控件組合成的布局,並且經常需要復用。比如下圖中 qq或者微博的title欄,在一款app中,可能不同的界面 類似的vie
本節引言: 好的,上一節中,我們又寫了一個關於Xfermode圖片混排的例子——擦美女衣服的Demo,加上前面的 利用Xfermode
由於Linux系統的權限限制和Android封裝架構限制,很多涉及底層設備、接口、驅動控制的應用開發,不得不使用到本文的NDK開發環境(基於Android源碼或內核源碼修