android 图片缩放

来源:互联网 发布:一建刷题软件 编辑:程序博客网 时间:2024/05/23 12:09
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;}}}}

0 0
原创粉丝点击