通过多点触控实现图片的放大、缩小、旋转、位移效果。
private float oldX1 = 0;
private float oldX2 = 0;
private float oldY1 = 0;
private float oldY2 = 0;
private float oldRotation= 0;
private boolean isDRAG = true;
private float downX = 0;
private float downY = 0;
@Override
public boolean onTouchEvent(MotionEvent event) {
int DEFAULT_MOVE = 10;// 手指移动小于该值认为没有移动
//必须要& MotionEvent.ACTION_MASK 才能触发
//ACTION_POINTER_DOWN
switch (event.getAction()& MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
if (listener!=null)
listener.onUse(true);
oldX1 = event.getX();
oldY1 = event.getY();
downX = event.getX();
downY = event.getY();
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldRotation = rotation(event);
oldX1 = event.getX(0);
oldX2 = event.getX(1);
oldY1 = event.getY(0);
oldY2 = event.getY(1);
break;
case MotionEvent.ACTION_MOVE:
/**
* 判断是否多点触控
*/
if (event.getPointerCount()>=2){
/**
* 判断是否点击后没有移动
*/
isDRAG = false;
float nowDifferentX = Math.abs(event.getX(0) - event.getX(1));
float oldDifferentX = Math.abs(oldX1 - oldX2);
float nowDifferentY = Math.abs(event.getY(0) - event.getY(1));
float oldDifferentY = Math.abs(oldY1 - oldY2);
//判断放大缩小
if (nowDifferentX - oldDifferentX > 0 && nowDifferentY - oldDifferentY > 0) {
/**
* 放大
*/
float multiples = 1 + MULTIPLES;
matrix.postScale(multiples, multiples, convertCenterX(), convertCenterY());
} else if (nowDifferentX - oldDifferentX < 0 && nowDifferentY - oldDifferentY < 0){
/**
* 缩小
*/
float multiples = 1 - MULTIPLES;
matrix.postScale(multiples, multiples, convertCenterX(), convertCenterY());
}
/**
* rotation当前旋转角度
*/
//判断旋转
float nowRotation = rotation(event);
float rotation = nowRotation - oldRotation;
matrix.postRotate(rotation, convertCenterX(), convertCenterY());// 旋轉
oldX1 = event.getX(0);
oldX2 = event.getX(1);
oldRotation += rotation;
}else if (isDRAG){
/**
* 单指移动
* 添加标识isDRAG 防止当多点触控其中一只手指离开时 变成单点
*/
matrix.postTranslate(event.getX() - oldX1, event.getY() - oldY1);
oldX1 = event.getX();
oldY1 = event.getY();
}
invalidate();
break;
case MotionEvent.ACTION_UP:
if (event.getPointerCount() == 1) {
isDRAG = true;
if (listener!=null)
listener.onUse(false);
/**
* 判断是否点击后没有移动
*/
if (Math.abs(event.getX() - downX) < DEFAULT_MOVE && Math.abs(event.getY() - downY) < DEFAULT_MOVE
&& needHead) {
startToAlbum();
}
}
break;
}
return true;
}
优化版:旋转和放大操作同时只能响应一个,旋转放大原点基于手指位置计算
@Override
public boolean onTouchEvent(MotionEvent event) {
int DEFAULT_MOVE = 5;// 手指移动小于该值认为没有移动
//必须要& MotionEvent.ACTION_MASK 才能触发
//ACTION_POINTER_DOWN
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
if (listener != null)
listener.onUse(true);
oldX1 = event.getX();
oldY1 = event.getY();
downX = event.getX();
downY = event.getY();
break;
case MotionEvent.ACTION_POINTER_DOWN:
isOne = true;
isScale = false;
isRotate = false;
isDRAG = false;
oldRotation = rotation(event);
oldX1 = event.getX(0);
oldX2 = event.getX(1);
oldY1 = event.getY(0);
oldY2 = event.getY(1);
float nowDifferentX = Math.abs(event.getX(0) - event.getX(1));
float nowDifferentY = Math.abs(event.getY(0) - event.getY(1));
mPx = nowDifferentX / 2 + Math.min(event.getX(0), event.getX(1));
mPy = nowDifferentY / 2 + Math.min(event.getY(0), event.getY(1));
break;
case MotionEvent.ACTION_MOVE:
/**
* 判断是否多点触控
*/
if (event.getPointerCount() >= 2) {
/**
* 放大缩小
* 旋转
* 同时只能存在一种
*/
if (isOne) {
isScale = scale(event, false);
isRotate = rotate(event, false);
if (isScale || isRotate) {
isOne = false;
}
}
if (isScale && !isRotate) {
scale(event, true);
} else if (!isScale && isRotate) {
rotate(event, true);
} else if (isRotate) {
scale(event, true);
}
oldX1 = event.getX(0);
oldX2 = event.getX(1);
oldY1 = event.getY(0);
oldY2 = event.getY(1);
} else if (isDRAG) {
/**
* 单指移动
* 添加标识isDRAG 防止当多点触控其中一只手指离开时 变成单点
*/
// LogUtil.setLog("transX: " + (event.getX(0) - oldX1) + " transY: " + (event.getY(0) - oldY1) + " oldX:" + oldX1 + " oldY: " + oldY1 + " X: " + event.getX(0) + " Y: " + event.getY(0) + " count: " + event.getPointerCount());
matrix.postTranslate(event.getX(0) - oldX1, event.getY(0) - oldY1);
oldX1 = event.getX(0);
oldY1 = event.getY(0);
}
invalidate();
break;
case MotionEvent.ACTION_UP:
if (event.getPointerCount() == 1) {
if (listener != null)
listener.onUse(false);
/**
* 判断是否点击后没有移动
*/
if (Math.abs(event.getX() - downX) < DEFAULT_MOVE && Math.abs(event.getY() - downY) < DEFAULT_MOVE
&& needHead && isDRAG) {
selectDialog.show();
}
isDRAG = true;
}
break;
}
return true;
}
/**
* @param isChange 是否需要改变视图
* @return 是否进行了放大缩小操作
*/
private boolean scale(MotionEvent event, boolean isChange) {
/**
* 判断是否点击后没有移动
* 两点间距离
*/
float nowDifferentX = Math.abs(event.getX(0) - event.getX(1));
float oldDifferentX = Math.abs(oldX1 - oldX2);
float nowDifferentY = Math.abs(event.getY(0) - event.getY(1));
float oldDifferentY = Math.abs(oldY1 - oldY2);
float changeX = nowDifferentX - oldDifferentX;
float changeY = nowDifferentY - oldDifferentY;
//判断放大缩小
float max = Math.max(Math.abs(changeX), Math.abs(changeY));
if (changeX > 0 && changeY > 0) {
/**
* 放大
*/
if (isChange) {
float multiples = 1 + MULTIPLES * max;
matrix.postScale(multiples, multiples, mPx, mPy);
}
return true;
} else if (changeX < 0 && changeY < 0) {
/**
* 缩小
*/
if (isChange) {
float multiples = 1 - MULTIPLES * max;
matrix.postScale(multiples, multiples, mPx, mPy);
}
return true;
}
return false;
}
private boolean rotate(MotionEvent event, boolean isChange) {
/**
* rotation当前旋转角度
*/
//判断旋转
float nowRotation = rotation(event);
float rotation = nowRotation - oldRotation;
if (Math.abs(rotation) >= 1) {
if (isChange) {
matrix.postRotate(rotation, mPx, mPy);// 旋轉
oldRotation += rotation;
}
return true;
} else return false;
}
// 取旋转角度
private float rotation(MotionEvent event) {
double delta_x = (event.getX(0) - event.getX(1));
double delta_y = (event.getY(0) - event.getY(1));
double radians = Math.atan2(delta_y, delta_x);
return (float) Math.toDegrees(radians);
}
放大计算方法:
当判断多指触控时,记录下当前两指的坐标点,在MOVE事件触发后,计算当前两指之间的距离和两指位置改变之前的距离,并进行比较,若距离变大则为放大,若距离缩小则为缩小。
旋转计算方法:
// 取旋转角度
private float rotation(MotionEvent event) {
double delta_x = (event.getX(0) - event.getX(1));
double delta_y = (event.getY(0) - event.getY(1));
double radians = Math.atan2(delta_y, delta_x);
return (float) Math.toDegrees(radians);
}
通过以上方法获得当前两指形成的角度值,在判断多指触控时记录下初始角度,当触发move事件后重新计算角度值,其差值即为旋转了的角度。