標籤:
import android.content.Context;import android.graphics.Matrix;import android.graphics.Rect;import android.graphics.RectF;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.view.GestureDetector;import android.view.MotionEvent;import android.view.ScaleGestureDetector;import android.view.ScaleGestureDetector.OnScaleGestureListener;import android.view.View;import android.view.ViewConfiguration;import android.view.ViewTreeObserver.OnGlobalLayoutListener;import android.widget.ImageView;import android.view.View.OnTouchListener;/** * 縮放類 * * * * * * Matrix 的set,pre和post的區別 * * pre表示在隊頭插入一個方法 post表示在隊尾插入一個方法 set表示把當前隊列清空,並且總是位於隊列的最中間位置. * * 當執行了一次set後:pre方法總是插入到set前部的隊列的最前面,post方法總是插入到set後部的隊列的最後面 * * * ScaleGestureDetector 類 和多點觸控相關 * */// 介面用於捕獲圖片載入完成public class MyImageView extends ImageView implements OnGlobalLayoutListener,OnScaleGestureListener, OnTouchListener {// -------------------------------------------// 縮放// ------------------------------------------private Boolean isOnce = true;public static final float BASABLE_SCALE_RATE = 1.0f;// 初始化時的縮放值,也是最小的縮放值private float mInitScale;// 雙擊時縮放達到的值private float mMidScale;// 放大的極限private float mMaxScale;// 局針對象private Matrix mMatrix;// 獲得使用者多點觸控時縮放的比例private ScaleGestureDetector mScaleGestureDetector;// -------------------------------------------// 自由移動// ------------------------------------------// 記錄上一次多點觸控的數量private int mLastPointerCount;private float mLastX, mLastY;// 用於中心點的保留private int mTouchSlop;// 是否可移動private boolean isCanDrag;// 判斷private boolean isCheckLeftAndRight;private boolean isCheckTopAndBottom;// -------------------------------------------// 雙擊放大與縮小// ------------------------------------------private GestureDetector mGestureDetector;private boolean isAutoScale;// -------------------------------------------// 構造類// ------------------------------------------public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);mMatrix = new Matrix();setScaleType(ScaleType.MATRIX);mScaleGestureDetector = new ScaleGestureDetector(context, this);setOnTouchListener(this);mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();mGestureDetector = new GestureDetector(context,new GestureDetector.SimpleOnGestureListener() {@Overridepublic boolean onDoubleTap(MotionEvent e) {if(isAutoScale){return true;}float x = e.getX();float y = e.getY();if (getScale() < mMidScale) {//mMatrix.postScale(mMidScale / getScale(), mMidScale/// getScale(), x, y);//setImageMatrix(mMatrix);postDelayed(new AutoScaleRunnable(mMidScale, x, y), 16);isAutoScale = true;} else {//mMatrix.postScale(mInitScale / getScale(),//mInitScale / getScale(), x, y);//setImageMatrix(mMatrix);postDelayed(new AutoScaleRunnable(mInitScale, x, y), 16);isAutoScale = true;}return true;}});}public MyImageView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public MyImageView(Context context) {this(context, null);}// 圖片載入到視窗完成@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();// View已經實現了這個介面,所以用thisgetViewTreeObserver().addOnGlobalLayoutListener(this);}@SuppressWarnings("deprecation")@Override// 圖片從視窗消失protected void onDetachedFromWindow() {super.onDetachedFromWindow();// 相容16一下的版本getViewTreeObserver().removeGlobalOnLayoutListener(this);}// 擷取ImageView載入完成的圖片@Overridepublic void onGlobalLayout() {if (isOnce) {// 獲得控制項的寬高int width = getWidth();int height = getHeight();// 或的圖片以及寬高Drawable d = getDrawable();if (d == null)return;int dw = d.getIntrinsicWidth();int dh = d.getIntrinsicHeight();// 縮放比例float scale = 1.0f;// 寬超出螢幕if (dw > width && dh < height) {scale = width * BASABLE_SCALE_RATE / dw;}// 高超出螢幕if (dh > height && dw < width) {scale = height * BASABLE_SCALE_RATE / dh;}// 同時超出螢幕 或 同時未超出 應調整到有一邊是滿邊距if ((dw < width && dh < height) || (dw > width && dh > height)) {scale = Math.min(width * BASABLE_SCALE_RATE / dw, height* BASABLE_SCALE_RATE / dh);}// 初始化時縮放的比例mInitScale = scale;mMaxScale = 4 * mInitScale;mMidScale = 2 * mInitScale;/** * * 將圖片移動到控制項的中心 */// 需要移動的寬高int dx = width / 2 - dw / 2;int dy = height / 2 - dh / 2;// 利用矩陣,對映像進行移動 等操作mMatrix.postTranslate(dx, dy);mMatrix.postScale(mInitScale, mInitScale, width / 2, height / 2);setImageMatrix(mMatrix);isOnce = false;} else {}}/** * 擷取當前的縮放比例 * * 此方法不甚瞭解 * */public float getScale() {float values[] = new float[9];mMatrix.getValues(values);return values[Matrix.MSCALE_X];}// 縮放中@Overridepublic boolean onScale(ScaleGestureDetector detector) {// scaleFactor 是縮放的值float scaleFactor = detector.getScaleFactor();float scale = getScale();if (getDrawable() == null) {return true;}// 縮放範圍的控制if ((scale < mMaxScale && scaleFactor > 1.0f)|| (scale > mInitScale && scaleFactor < 1.0f)) {// 縮得特別小小if (scale * scaleFactor < mInitScale) {scaleFactor = mInitScale / scale;}// 放的特別大if (scale * scaleFactor > mMaxScale) {scale = mMaxScale / scale;}// 縮放mMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(),detector.getFocusY());// 防止出現白邊,並置中checkBorderAndCenter();setImageMatrix(mMatrix);}return false;}// 此處應該設定為true@Overridepublic boolean onScaleBegin(ScaleGestureDetector detector) {return true;}@Overridepublic void onScaleEnd(ScaleGestureDetector detector) {}// 利用觸摸事件,mScaleGestureDetector獲得多個焦點座標,以便實現多點觸控@Overridepublic boolean onTouch(View v, MotionEvent event) {if (mGestureDetector.onTouchEvent(event))return true;mScaleGestureDetector.onTouchEvent(event);// x,y是中心點的位置float x = 0, y = 0;// 多點觸控的數量int pointerCount = event.getPointerCount();for (int i = 0; i < pointerCount; i++) {x += event.getX(i);y += event.getY(i);isCanDrag = false;}x /= pointerCount;y /= pointerCount;// 觸控點個數發生改變if (mLastPointerCount != pointerCount) {mLastX = x;mLastY = y;mLastPointerCount = pointerCount;}switch (event.getAction()) {case MotionEvent.ACTION_MOVE:float dx = x - mLastX;float dy = y - mLastY;if (!isCanDrag) {isCanDrag = isMoveAction(dx, dy);}if (isCanDrag) {RectF rectF = getMatrixRectF();if (getDrawable() != null) {isCheckLeftAndRight = isCheckTopAndBottom = true;// 寬度小於控制項寬度,不允許移動if (rectF.width() < getWidth()) {dx = 0;isCheckLeftAndRight = false;}// 高度小於控制項高度,不允許移動if (rectF.height() < getHeight()) {dy = 0;isCheckTopAndBottom = false;}mMatrix.postTranslate(dx, dy);checkBorderWhenTranslate();setImageMatrix(mMatrix);}}mLastX = x;mLastY = y;break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:mLastPointerCount = 0;break;}return true;}/** * 當移動時 進行邊界檢查 * */private void checkBorderWhenTranslate() {RectF rectf = getMatrixRectF();float deltaX = 0;float deltaY = 0;int width = getWidth();int height = getHeight();if (rectf.top > 0 && isCheckTopAndBottom) {deltaY = -rectf.top;}if (rectf.bottom < height && isCheckTopAndBottom) {deltaY = height - rectf.bottom;}if (rectf.left > 0 && isCheckLeftAndRight) {deltaX = -rectf.left;}if (rectf.right < width && isCheckLeftAndRight) {deltaX = width - rectf.right;}mMatrix.postTranslate(deltaX, deltaY);}/** * 是否是move */private boolean isMoveAction(float dx, float dy) {return Math.sqrt(dx * dx + dy * dy) > mTouchSlop;}// Rect是矩形,邊界是float,所以是RectF// 此方法用來RectF對象來獲得放大縮小後的寬高public RectF getMatrixRectF() {Matrix matrix = mMatrix;RectF rectF = new RectF();Drawable d = getDrawable();if (d != null) {rectF.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());matrix.mapRect(rectF);}return rectF;}// 在縮放時對邊界的控制public void checkBorderAndCenter() {RectF rectF = getMatrixRectF();// 超出螢幕的長度float deltaX = 0;float deltaY = 0;int width = getWidth();int height = getHeight();// 邊界檢測,防止出現白邊if (rectF.width() >= width) {// 左邊出現空白if (rectF.left > 0) {deltaX = -rectF.left;}// 右邊出現空白if (rectF.right < width) {deltaX = width - rectF.right;}}if (rectF.height() >= height) {if (rectF.top > 0) {deltaY = -rectF.top;}if (rectF.bottom < width) {deltaY = height - rectF.bottom;}}// 如果圖片的寬高小於控制項的寬高,則讓其置中顯示if (rectF.width() < width) {deltaX = width / 2f - rectF.right + rectF.width() / 2f;}if (rectF.height() < height) {deltaY = height / 2f - rectF.bottom + rectF.height() / 2f;}mMatrix.postTranslate(deltaX, deltaY);}/** * 自動縮放 * * */private class AutoScaleRunnable implements Runnable {// 縮放的目標值private float mTargetScale;// 縮放的中心點private float x;private float y;private final float BIGGER = 1.07f;private final float SMALL =0.93f;private float tmpScale;public AutoScaleRunnable(float mTargetScale, float x, float y) {super();this.mTargetScale = mTargetScale;this.x = x;this.y = y;if (getScale() > mTargetScale) {tmpScale = BIGGER;}if (getScale() < mTargetScale) {tmpScale = SMALL;}}public void run() {//進行縮放 mMatrix.postScale(tmpScale, tmpScale, x, y);checkBorderAndCenter();setImageMatrix(mMatrix);float currentScale = getScale();if ((tmpScale > 1.0f && currentScale < mTargetScale)|| (tmpScale < 1.0f && currentScale > mTargetScale)) {postDelayed(this, 16);} else {float scale = mTargetScale/currentScale;mMatrix.postScale(scale, scale, x, y);checkBorderAndCenter();setImageMatrix(mMatrix);isAutoScale = false;}}}}
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
android 圖片縮放