Android(安卓)多点触控(放大、缩小、旋转、位移)
16lz
2021-01-24
通过多点触控实现图片的放大、缩小、旋转、位移效果。
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事件后重新计算角度值,其差值即为旋转了的角度。
更多相关文章
- Android圆形进度显示控件的SectorProgressView的使用
- Linux/Android(安卓)多点触摸支持
- 从android角度看2D加速图形引擎
- Android(安卓)源码系列之从源码的角度深入理解IntentService及Ha
- android 问题汇总系列之七
- Android(安卓)进阶学习:事件分发机制完全解析,带你从源码的角度彻
- 2011.10.12(2)——— android Matrix学习01
- Android(安卓)Activity跳转出现白屏但不闪退的现象
- 从源码角度理解HandlerThread和IntentService