實現技術主要用到1、多點觸摸 2、matrix的矩陣,平移、縮放
根據手指的數量判斷是進行的拖動、還是縮放動作
package com.bi.xintest; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.PointF; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.FloatMath; import android.util.Log; import android.view.MotionEvent; import android.widget.ImageView; public class ScaleView extends ImageView { final public static int DRAG = 1; final public static int ZOOM = 2; public int mode = 0; private Matrix matrix = new Matrix(); private Matrix matrix1 = new Matrix(); private Matrix saveMatrix = new Matrix(); private float x_down = 0; private float y_down = 0; private Bitmap touchImg = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher); private PointF mid = new PointF(); private float initDis = 1f; private int screenWidth, screenHeight; private float[] x = new float[4]; private float[] y = new float[4]; private boolean flag = false; public ScaleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public ScaleView(Context context, AttributeSet attrs) { super(context, attrs); } public ScaleView(Context context) { super(context); touchImg = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher); DisplayMetrics dm = getResources().getDisplayMetrics(); screenWidth = dm.widthPixels; screenHeight = dm.heightPixels; matrix = new Matrix(); // this.setScaleType(ScaleType.MATRIX); } @Override protected void onDraw(Canvas canvas) { canvas.save(); // 根據 matrix 來重繪新的view canvas.drawBitmap(touchImg, matrix, null); canvas.restore(); } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); // 多點觸摸的時候 必須加上MotionEvent.ACTION_MASK switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: saveMatrix.set(matrix); x_down = event.getX(); y_down = event.getY(); // 初始為drag模式 mode = DRAG; break; case MotionEvent.ACTION_POINTER_DOWN: saveMatrix.set(matrix); // 初始的兩個觸摸點間的距離 initDis = spacing(event); // 設置為縮放模式 mode = ZOOM; // 多點觸摸的時候 計算出中間點的坐標 midPoint(mid, event); break; case MotionEvent.ACTION_MOVE: // drag模式 if (mode == DRAG) { // 設置當前的 matrix matrix1.set(saveMatrix); // 平移 當前坐標減去初始坐標 移動的距離 matrix1.postTranslate(event.getX() - x_down, event.getY() - y_down);// 平移 // 判斷達到移動標准 flag = checkMatrix(matrix1); if (flag) { // 設置matrix matrix.set(matrix1); // 調用ondraw重繪 invalidate(); } } else if (mode == ZOOM) { matrix1.set(saveMatrix); float newDis = spacing(event); // 計算出縮放比例 float scale = newDis / initDis; // 以mid為中心進行縮放 matrix1.postScale(scale, scale, mid.x, mid.y); flag = checkMatrix(matrix1); if (flag) { matrix.set(matrix1); invalidate(); } } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_UP: mode = 0; break; } return true; } //取兩點的距離 private float spacing(MotionEvent event) { try { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return (float)Math.sqrt(x * x + y * y); } catch (IllegalArgumentException ex) { Log.v("TAG", ex.getLocalizedMessage()); return 0; } } //取兩點的中點 private void midPoint(PointF point, MotionEvent event) { try { float x = event.getX(0) + event.getX(1); float y = event.getY(0) + event.getY(1); point.set(x / 2, y / 2); } catch (IllegalArgumentException ex) { //這個異常是android自帶的,網上清一色的這么說。。。。 Log.v("TAG", ex.getLocalizedMessage()); } } private boolean checkMatrix(Matrix m) { GetFour(m); // 出界判斷 //view的右邊緣x坐標小於屏幕寬度的1/3的時候, // view左邊緣大於屏幕款短的2/3的時候 //view的下邊緣在屏幕1/3上的時候 //view的上邊緣在屏幕2/3下的時候 if ((x[0] < screenWidth / 3 && x[1] < screenWidth / 3 && x[2] < screenWidth / 3 && x[3] < screenWidth / 3) || (x[0] > screenWidth * 2 / 3 && x[1] > screenWidth * 2 / 3 && x[2] > screenWidth * 2 / 3 && x[3] > screenWidth * 2 / 3) || (y[0] < screenHeight / 3 && y[1] < screenHeight / 3 && y[2] < screenHeight / 3 && y[3] < screenHeight / 3) || (y[0] > screenHeight * 2 / 3 && y[1] > screenHeight * 2 / 3 && y[2] > screenHeight * 2 / 3 && y[3] > screenHeight * 2 / 3)) { return true; } // 圖片現寬度 double width = Math.sqrt((x[0] - x[1]) * (x[0] - x[1]) + (y[0] - y[1]) * (y[0] - y[1])); // 縮放比率判斷 寬度打雨3倍屏寬,或者小於1/3屏寬 if (width < screenWidth / 3 || width > screenWidth * 3) { return true; } return false; // if ((x[0] >= 0 && x[1] >= 0 && x[2] >= 0 && x[3] >= 0) // && (x[0] <= screenWidth && x[1] <= screenWidth // && x[2] <= screenWidth && x[3] <= screenWidth) // && (y[0] >= 0 && y[1] >= 0 && y[2] >= 0 && y[3] >= 0) && (y[0] <= // screenHeight // && y[1] <= screenHeight && y[2] <= screenHeight && y[3] <= // screenHeight)) { // // return true; // } // // return false; } private void GetFour(Matrix matrix) { float[] f = new float[9]; matrix.getValues(f); // StringBuffer sb = new StringBuffer(); // for(float ff : f) // { // sb.append(ff+" "); // } // 圖片4個頂點的坐標 //矩陣 9 MSCALE_X 縮放的, MSKEW_X 傾斜的 。MTRANS_X 平移的 x[0] = f[Matrix.MSCALE_X] * 0 + f[Matrix.MSKEW_X] * 0 + f[Matrix.MTRANS_X]; y[0] = f[Matrix.MSKEW_Y] * 0 + f[Matrix.MSCALE_Y] * 0 + f[Matrix.MTRANS_Y]; x[1] = f[Matrix.MSCALE_X] * touchImg.getWidth() + f[Matrix.MSKEW_X] * 0 + f[Matrix.MTRANS_X]; y[1] = f[Matrix.MSKEW_Y] * touchImg.getWidth() + f[Matrix.MSCALE_Y] * 0 + f[Matrix.MTRANS_Y]; x[2] = f[Matrix.MSCALE_X] * 0 + f[Matrix.MSKEW_X] * touchImg.getHeight() + f[Matrix.MTRANS_X]; y[2] = f[Matrix.MSKEW_Y] * 0 + f[Matrix.MSCALE_Y] * touchImg.getHeight() + f[Matrix.MTRANS_Y]; x[3] = f[Matrix.MSCALE_X] * touchImg.getWidth() + f[Matrix.MSKEW_X] * touchImg.getHeight() + f[Matrix.MTRANS_X]; y[3] = f[Matrix.MSKEW_Y] * touchImg.getWidth() + f[Matrix.MSCALE_Y] * touchImg.getHeight() + f[Matrix.MTRANS_Y]; } }