Android 多点触控(放大、缩小、旋转、位移)

通过多点触控实现图片的放大、缩小、旋转、位移效果。


    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,UI)