标签:
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() { @Override public 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); } // 图片加载到窗口完成 @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); // View已经实现了这个接口,所以用this getViewTreeObserver().addOnGlobalLayoutListener(this); } @SuppressWarnings("deprecation") @Override // 图片从窗口消失 protected void onDetachedFromWindow() { super.onDetachedFromWindow(); // 兼容16一下的版本 getViewTreeObserver().removeGlobalOnLayoutListener(this); } // 获取ImageView加载完成的图片 @Override public 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]; } // 缩放中 @Override public 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 @Override public boolean onScaleBegin(ScaleGestureDetector detector) { return true; } @Override public void onScaleEnd(ScaleGestureDetector detector) { } // 利用触摸事件,mScaleGestureDetector获得多个焦点坐标,以便实现多点触控 @Override public 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; } } } }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/u012282088/article/details/47317275