自定义View(三)实现简单的可拖动、可缩放的ImageView

时间:2023-12-26 23:12:43

实现技术主要用到1、多点触摸  2、matrix的矩阵,平移、缩放

根据手指的数量判断是进行的拖动、还是缩放动作

package com.bi.xintest;

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.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 = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher); 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.mipmap.ic_launcher);
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 (float)Math.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];
} }