`

android view的缩放平移简单实现

 
阅读更多
参考了下网上一些实现

主要是通过matrix实现的

用到的技术点:1,多点触摸
2,matrix的矩阵,平移和缩放


package com.nico;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;

public class ScaleView extends ImageView {

	final public static int DRAG = 1;
	final public static int ZOOM = 2;

	public int mode = 0;

	private Matrix matrix = new Matrix();
	private Matrix matrix1 = new Matrix();
	private Matrix saveMatrix = new Matrix();

	private float x_down = 0;
	private float y_down = 0;

	private Bitmap touchImg;

	private PointF mid = new PointF();


	private float initDis = 1f;

	private int screenWidth, screenHeight;

	private float[] x = new float[4];
	private float[] y = new float[4];

	private boolean flag = false;

	public ScaleView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
	}

	public ScaleView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public ScaleView(Context context) {
		super(context);
		touchImg = BitmapFactory.decodeResource(getResources(), R.drawable.img);
		DisplayMetrics dm = getResources().getDisplayMetrics();
		screenWidth = dm.widthPixels;
		screenHeight = dm.heightPixels;
		matrix = new Matrix();
		// this.setScaleType(ScaleType.MATRIX);
	}

	@Override
	protected void onDraw(Canvas canvas) {

		canvas.save();
		// 根据 matrix 来重绘新的view
		canvas.drawBitmap(touchImg, matrix, null);
		canvas.restore();
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {

		int action = event.getAction();
		// 多点触摸的时候 必须加上MotionEvent.ACTION_MASK
		switch (action & MotionEvent.ACTION_MASK) {
		case MotionEvent.ACTION_DOWN:
			saveMatrix.set(matrix);
			x_down = event.getX();
			y_down = event.getY();
			// 初始为drag模式
			mode = DRAG;
			break;

		case MotionEvent.ACTION_POINTER_DOWN:
			saveMatrix.set(matrix);
			// 初始的两个触摸点间的距离
			initDis = spacing(event);
			// 设置为缩放模式
			mode = ZOOM;
			// 多点触摸的时候 计算出中间点的坐标
			midPoint(mid, event);
			break;

		case MotionEvent.ACTION_MOVE:

			// drag模式
			if (mode == DRAG) {
				// 设置当前的 matrix
				matrix1.set(saveMatrix);
				// 平移 当前坐标减去初始坐标 移动的距离
				matrix1.postTranslate(event.getX() - x_down, event.getY()
						- y_down);// 平移
				// 判断达到移动标准
				flag = checkMatrix(matrix1);
				if (flag) {
					// 设置matrix
					matrix.set(matrix1);

					// 调用ondraw重绘
					invalidate();
				}
			} else if (mode == ZOOM) {
				matrix1.set(saveMatrix);
				float newDis = spacing(event);
				// 计算出缩放比例
				float scale = newDis / initDis;

				// 以mid为中心进行缩放
				matrix1.postScale(scale, scale, mid.x, mid.y);
				flag = checkMatrix(matrix1);
				if (flag) {
					matrix.set(matrix1);
					invalidate();
				}
			}
			break;

		case MotionEvent.ACTION_UP:
		case MotionEvent.ACTION_POINTER_UP:
			mode = 0;
			break;
		}

		return true;

	}

	//取两点的距离
	private float spacing(MotionEvent event) {
		try {
			float x = event.getX(0) - event.getX(1);
			float y = event.getY(0) - event.getY(1);
			return FloatMath.sqrt(x * x + y * y);
		} catch (IllegalArgumentException ex) {
			Log.v("TAG", ex.getLocalizedMessage());
			return 0;
		}
	}

	//取两点的中点
	private void midPoint(PointF point, MotionEvent event) {
		try {
			float x = event.getX(0) + event.getX(1);
			float y = event.getY(0) + event.getY(1);
			point.set(x / 2, y / 2);
		} catch (IllegalArgumentException ex) {

			//这个异常是android自带的,网上清一色的这么说。。。。
			Log.v("TAG", ex.getLocalizedMessage());
		}
	}

	private boolean checkMatrix(Matrix m) {

		GetFour(m);

		// 出界判断  
		//view的右边缘x坐标小于屏幕宽度的1/3的时候,
		// view左边缘大于屏幕款短的2/3的时候
		//view的下边缘在屏幕1/3上的时候
		//view的上边缘在屏幕2/3下的时候
		if ((x[0] < screenWidth / 3 && x[1] < screenWidth / 3
				&& x[2] < screenWidth / 3 && x[3] < screenWidth / 3)
				|| (x[0] > screenWidth * 2 / 3 && x[1] > screenWidth * 2 / 3
						&& x[2] > screenWidth * 2 / 3 && x[3] > screenWidth * 2 / 3)
						|| (y[0] < screenHeight / 3 && y[1] < screenHeight / 3
								&& y[2] < screenHeight / 3 && y[3] < screenHeight / 3)
								|| (y[0] > screenHeight * 2 / 3 && y[1] > screenHeight * 2 / 3
										&& y[2] > screenHeight * 2 / 3 && y[3] > screenHeight * 2 / 3)) {
			return true;
		}
		// 图片现宽度
		double width = Math.sqrt((x[0] - x[1]) * (x[0] - x[1]) + (y[0] - y[1])
				* (y[0] - y[1]));
		// 缩放比率判断 宽度打雨3倍屏宽,或者小于1/3屏宽
		if (width < screenWidth / 3 || width > screenWidth * 3) {
			return true;
		}
		return false;

		// if ((x[0] >= 0 && x[1] >= 0 && x[2] >= 0 && x[3] >= 0)
		// && (x[0] <= screenWidth && x[1] <= screenWidth
		// && x[2] <= screenWidth && x[3] <= screenWidth)
		// && (y[0] >= 0 && y[1] >= 0 && y[2] >= 0 && y[3] >= 0) && (y[0] <=
		// screenHeight
		// && y[1] <= screenHeight && y[2] <= screenHeight && y[3] <=
		// screenHeight)) {
		//
		// return true;
		// }
		//
		// return false;
	}

	private void GetFour(Matrix matrix) {
		float[] f = new float[9];
		matrix.getValues(f);
//		StringBuffer sb = new StringBuffer();
//		for(float ff : f)
//		{
//			sb.append(ff+"  ");
//		}
		// 图片4个顶点的坐标
		//矩阵  9     MSCALE_X 缩放的, MSKEW_X 倾斜的    。MTRANS_X 平移的 
		x[0] = f[Matrix.MSCALE_X] * 0 + f[Matrix.MSKEW_X] * 0
				+ f[Matrix.MTRANS_X];
		y[0] = f[Matrix.MSKEW_Y] * 0 + f[Matrix.MSCALE_Y] * 0
				+ f[Matrix.MTRANS_Y];
		x[1] = f[Matrix.MSCALE_X] * touchImg.getWidth() + f[Matrix.MSKEW_X] * 0
				+ f[Matrix.MTRANS_X];
		y[1] = f[Matrix.MSKEW_Y] * touchImg.getWidth() + f[Matrix.MSCALE_Y] * 0
				+ f[Matrix.MTRANS_Y];
		x[2] = f[Matrix.MSCALE_X] * 0 + f[Matrix.MSKEW_X]
				* touchImg.getHeight() + f[Matrix.MTRANS_X];
		y[2] = f[Matrix.MSKEW_Y] * 0 + f[Matrix.MSCALE_Y]
				* touchImg.getHeight() + f[Matrix.MTRANS_Y];
		x[3] = f[Matrix.MSCALE_X] * touchImg.getWidth() + f[Matrix.MSKEW_X]
				* touchImg.getHeight() + f[Matrix.MTRANS_X];
		y[3] = f[Matrix.MSKEW_Y] * touchImg.getWidth() + f[Matrix.MSCALE_Y]
				* touchImg.getHeight() + f[Matrix.MTRANS_Y];
	}

}

分享到:
评论
1 楼 usedlie 2016-06-17  
if (flag) { 
matrix.set(matrix1); 
invalidate(); 
}

这个逻辑反了,private boolean checkMatrix(Matrix m)这个方法是越界判断,假如越界,则返回true;


谢谢博主的GetFour(Matrix matrix)这个方法,正愁找不到缩放后的图片的坐标呢。。
一开始还以为得记录用户的一切操作(比如偏移量,缩放什么的),帮了大忙,谢谢;

虽说网上不少缩放、移动的控件,不过还是这种自定义的才能满足各种蛋疼的需求;

下一步看看要不要优化中心点=。=

相关推荐

Global site tag (gtag.js) - Google Analytics