android 图片缩放



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;
			}
		}

	}

}

发布了10 篇原创文章 · 获赞 0 · 访问量 5819
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览