Android 多點觸控(放大、縮小、旋轉、位移)
阿新 • • 發佈:2019-01-26
通過多點觸控實現圖片的放大、縮小、旋轉、位移效果。
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事件觸發後,計算當前兩指之間的距離和兩指位置改變之前的距離,並進行比較,若距離變大則為放大,若距離縮小則為縮小。
旋轉計算方法:
通過以上方法獲得當前兩指形成的角度值,在判斷多指觸控時記錄下初始角度,當觸發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); }