標籤:
package com.msstudent.view;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Matrix;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.widget.ImageView;/** * 自訂的ImageView控制,可對圖片進行多點觸控縮放和拖動 * * @author guolin */public class ZoomImageView extends ImageView {/** * 初始化狀態常量 */public static final int STATUS_INIT = 1;/** * 圖片放大狀態常量 */public static final int STATUS_ZOOM_OUT = 2;/** * 圖片縮小狀態常量 */public static final int STATUS_ZOOM_IN = 3;/** * 圖片拖動狀態常量 */public static final int STATUS_MOVE = 4;/** * 用於對圖片進行移動和縮放變換的矩陣 */private Matrix matrix = new Matrix();/** * 待展示的Bitmap對象 */private Bitmap sourceBitmap;/** * 記錄當前操作的狀態,可選值為STATUS_INIT、STATUS_ZOOM_OUT、STATUS_ZOOM_IN和STATUS_MOVE */private int currentStatus;/** * ZoomImageView控制項的寬度 */private int width;/** * ZoomImageView控制項的高度 */private int height;/** * 記錄兩指同時放在螢幕上時,中心點的橫座標值 */private float centerPointX;/** * 記錄兩指同時放在螢幕上時,中心點的縱座標值 */private float centerPointY;/** * 記錄當前圖片的寬度,圖片被縮放時,這個值會一起變動 */private float currentBitmapWidth;/** * 記錄當前圖片的高度,圖片被縮放時,這個值會一起變動 */private float currentBitmapHeight;/** * 記錄上次手指移動時的橫座標 */private float lastXMove = -1;/** * 記錄上次手指移動時的縱座標 */private float lastYMove = -1;/** * 記錄手指在橫座標方向上的移動距離 */private float movedDistanceX;/** * 記錄手指在縱座標方向上的移動距離 */private float movedDistanceY;/** * 記錄圖片在矩陣上的橫向位移值 */private float totalTranslateX;/** * 記錄圖片在矩陣上的縱向位移值 */private float totalTranslateY;/** * 記錄圖片在矩陣上的總縮放比例 */private float totalRatio;/** * 記錄手指移動的距離所造成的縮放比例 */private float scaledRatio;/** * 記錄圖片初始化時的縮放比例 */private float initRatio;/** * 記錄上次兩指之間的距離 */private double lastFingerDis;/** * ZoomImageView建構函式,將當前操作狀態設為STATUS_INIT。 * * @param context * @param attrs */public ZoomImageView(Context context, AttributeSet attrs) {super(context, attrs);currentStatus = STATUS_INIT;}/** * 將待展示的圖片設定進來。 * * @param bitmap * 待展示的Bitmap對象 */public void setImageBitmap(Bitmap bitmap) {sourceBitmap = bitmap;invalidate();}@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {super.onLayout(changed, left, top, right, bottom);if (changed) {// 分別擷取到ZoomImageView的寬度和高度width = getWidth();height = getHeight();}}@Overridepublic boolean onTouchEvent(MotionEvent event) {if (initRatio == totalRatio) {getParent().requestDisallowInterceptTouchEvent(false);} else {getParent().requestDisallowInterceptTouchEvent(true);}switch (event.getActionMasked()) {case MotionEvent.ACTION_POINTER_DOWN:if (event.getPointerCount() == 2) {// 當有兩個手指按在螢幕上時,計算兩指之間的距離lastFingerDis = distanceBetweenFingers(event);}break;case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_MOVE:if (event.getPointerCount() == 1) {// 只有單指按在螢幕上移動時,為拖動狀態float xMove = event.getX();float yMove = event.getY();if (lastXMove == -1 && lastYMove == -1) {lastXMove = xMove;lastYMove = yMove;}currentStatus = STATUS_MOVE;movedDistanceX = xMove - lastXMove;movedDistanceY = yMove - lastYMove;// 進行邊界檢查,不允許將圖片拖出邊界if (totalTranslateX + movedDistanceX > 0) {movedDistanceX = 0;} else if (width - (totalTranslateX + movedDistanceX) > currentBitmapWidth) {movedDistanceX = 0;}if (totalTranslateY + movedDistanceY > 0) {movedDistanceY = 0;} else if (height - (totalTranslateY + movedDistanceY) > currentBitmapHeight) {movedDistanceY = 0;}// 調用onDraw()方法繪製圖片invalidate();lastXMove = xMove;lastYMove = yMove;} else if (event.getPointerCount() == 2) {// 有兩個手指按在螢幕上移動時,為縮放狀態centerPointBetweenFingers(event);double fingerDis = distanceBetweenFingers(event);if (fingerDis > lastFingerDis) {currentStatus = STATUS_ZOOM_OUT;} else {currentStatus = STATUS_ZOOM_IN;}// 進行縮放倍數檢查,最大隻允許將圖片放大4倍,最小可以縮小到初始化比例if ((currentStatus == STATUS_ZOOM_OUT && totalRatio < 4 * initRatio)|| (currentStatus == STATUS_ZOOM_IN && totalRatio > initRatio)) {scaledRatio = (float) (fingerDis / lastFingerDis);totalRatio = totalRatio * scaledRatio;if (totalRatio > 4 * initRatio) {totalRatio = 4 * initRatio;} else if (totalRatio < initRatio) {totalRatio = initRatio;}// 調用onDraw()方法繪製圖片invalidate();lastFingerDis = fingerDis;}}break;case MotionEvent.ACTION_POINTER_UP:if (event.getPointerCount() == 2) {// 手指離開螢幕時將臨時值還原lastXMove = -1;lastYMove = -1;}break;case MotionEvent.ACTION_UP:// 手指離開螢幕時將臨時值還原lastXMove = -1;lastYMove = -1;break;default:break;}return true;}/** * 根據currentStatus的值來決定對圖片進行什麼樣的繪製操作。 */@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);switch (currentStatus) {case STATUS_ZOOM_OUT:case STATUS_ZOOM_IN:zoom(canvas);break;case STATUS_MOVE:move(canvas);break;case STATUS_INIT:initBitmap(canvas);default:if (sourceBitmap != null) {canvas.drawBitmap(sourceBitmap, matrix, null);}break;}}/** * 對圖片進行縮放處理。 * * @param canvas */private void zoom(Canvas canvas) {matrix.reset();// 將圖片按總縮放比例進行縮放matrix.postScale(totalRatio, totalRatio);float scaledWidth = sourceBitmap.getWidth() * totalRatio;float scaledHeight = sourceBitmap.getHeight() * totalRatio;float translateX = 0f;float translateY = 0f;// 如果當前圖片寬度小於螢幕寬度,則按螢幕中心的橫座標進行水平縮放。否則按兩指的中心點的橫座標進行水平縮放if (currentBitmapWidth < width) {translateX = (width - scaledWidth) / 2f;} else {translateX = totalTranslateX * scaledRatio + centerPointX* (1 - scaledRatio);// 進行邊界檢查,保證圖片縮放後在水平方向上不會位移出螢幕if (translateX > 0) {translateX = 0;} else if (width - translateX > scaledWidth) {translateX = width - scaledWidth;}}// 如果當前圖片高度小於螢幕高度,則按螢幕中心的縱座標進行垂直縮放。否則按兩指的中心點的縱座標進行垂直縮放if (currentBitmapHeight < height) {translateY = (height - scaledHeight) / 2f;} else {translateY = totalTranslateY * scaledRatio + centerPointY* (1 - scaledRatio);// 進行邊界檢查,保證圖片縮放後在垂直方向上不會位移出螢幕if (translateY > 0) {translateY = 0;} else if (height - translateY > scaledHeight) {translateY = height - scaledHeight;}}// 縮放後對圖片進行位移,以保證縮放後中心點位置不變matrix.postTranslate(translateX, translateY);totalTranslateX = translateX;totalTranslateY = translateY;currentBitmapWidth = scaledWidth;currentBitmapHeight = scaledHeight;canvas.drawBitmap(sourceBitmap, matrix, null);}/** * 對圖片進行平移處理 * * @param canvas */private void move(Canvas canvas) {matrix.reset();// 根據手指移動的距離計算出總位移值float translateX = totalTranslateX + movedDistanceX;float translateY = totalTranslateY + movedDistanceY;// 先按照已有的縮放比例對圖片進行縮放matrix.postScale(totalRatio, totalRatio);// 再根據移動距離進行位移matrix.postTranslate(translateX, translateY);totalTranslateX = translateX;totalTranslateY = translateY;canvas.drawBitmap(sourceBitmap, matrix, null);}/** * 對圖片進行初始化操作,包括讓圖片置中,以及當圖片大於螢幕寬高時對圖片進行壓縮。 * * @param canvas */private void initBitmap(Canvas canvas) {if (sourceBitmap != null) {matrix.reset();int bitmapWidth = sourceBitmap.getWidth();int bitmapHeight = sourceBitmap.getHeight();if (bitmapWidth > width || bitmapHeight > height) {if (bitmapWidth - width > bitmapHeight - height) {// 當圖片寬度大於螢幕寬度時,將圖片等比例壓縮,使它可以完全顯示出來float ratio = width / (bitmapWidth * 1.0f);matrix.postScale(ratio, ratio);float translateY = (height - (bitmapHeight * ratio)) / 2f;// 在縱座標方向上進行位移,以保證圖片置中顯示matrix.postTranslate(0, translateY);totalTranslateY = translateY;totalRatio = initRatio = ratio;} else {// 當圖片高度大於螢幕高度時,將圖片等比例壓縮,使它可以完全顯示出來float ratio = height / (bitmapHeight * 1.0f);matrix.postScale(ratio, ratio);float translateX = (width - (bitmapWidth * ratio)) / 2f;// 在橫座標方向上進行位移,以保證圖片置中顯示matrix.postTranslate(translateX, 0);totalTranslateX = translateX;totalRatio = initRatio = ratio;}currentBitmapWidth = bitmapWidth * initRatio;currentBitmapHeight = bitmapHeight * initRatio;} else {// 當圖片的寬高都小於螢幕寬高時,直接讓圖片置中顯示float translateX = (width - sourceBitmap.getWidth()) / 2f;float translateY = (height - sourceBitmap.getHeight()) / 2f;matrix.postTranslate(translateX, translateY);totalTranslateX = translateX;totalTranslateY = translateY;totalRatio = initRatio = 1f;currentBitmapWidth = bitmapWidth;currentBitmapHeight = bitmapHeight;}canvas.drawBitmap(sourceBitmap, matrix, null);}}/** * 計算兩個手指之間的距離。 * * @param event * @return 兩個手指之間的距離 */private double distanceBetweenFingers(MotionEvent event) {float disX = Math.abs(event.getX(0) - event.getX(1));float disY = Math.abs(event.getY(0) - event.getY(1));return Math.sqrt(disX * disX + disY * disY);}/** * 計算兩個手指之間中心點的座標。 * * @param event */private void centerPointBetweenFingers(MotionEvent event) {float xPoint0 = event.getX(0);float yPoint0 = event.getY(0);float xPoint1 = event.getX(1);float yPoint1 = event.getY(1);centerPointX = (xPoint0 + xPoint1) / 2;centerPointY = (yPoint0 + yPoint1) / 2;}}代碼中的注釋寫的非常詳細了,可以根據自己項目需求進行修改
Android自訂imageview可對圖片進行多點縮放和拖動