android双指缩放和双指拖拽控件

author:andy

问题:产品要求,做成双指缩放且双指拖拽

android市面上应用最常见的一个功能是双指缩放,然后单指拖拽。比如最著名的PhotoView开源,就是典型代表。然而Google了半天基本找不到双指缩放和双指拖拽的完整资料,而且网上也有一些用户提出相同的问题,然而并没有好的开源,就自己整了个。

先上图:


gif.gif

思路流程图:


双指缩放和拖拽.jpg

注意的事项:
MotionEvent:对应的几个关键事件
MotionEvent.ACTION_POINTER_DOWN: 第二根以上手指触摸屏幕触发:
在第二个手指的监听记录初始位置,记录2个手指开始的间距oldDist:

 case MotionEvent.ACTION_POINTER_DOWN:
                if (pointerCount == 2) {
                    downX1 = event.getX(0);
                    downX2 = event.getX(1);
                    downY1 = event.getY(0);
                    downY2 = event.getY(1);
                    Log.d(TAG, "ACTION_POINTER_DOWN 双指按下 downX1=" + downX1 + " downX2="
                            + downX2 + "  downY1=" + downY1 + " downY2=" + downY2);
                    oldDist = spacing(event); //两点按下时的距离
                }

手指移动过程缩放和移动处理:
oldDist:2手指初始距离
moveDist: 2手指移动后的距离
space: 2手指变化距离
缩放比例:float scale = (float) (getScaleX() + space / v.getWidth());

移动处理:以2指中心点变化值作为移动范围

case MotionEvent.ACTION_MOVE:
               if (pointerCount == 2) {
                   float x1 = event.getX(0);
                   float x2 = event.getX(1);
                   float y1 = event.getY(0);
                   float y2 = event.getY(1);

                   double changeX1 = x1 - downX1;
                   double changeX2 = x2 - downX2;
                   double changeY1 = y1 - downY1;
                   double changeY2 = y2 - downY2;

                   if (getScaleX() > 1) { //滑动
                       float lessX = (float) ((changeX1) / 2 + (changeX2) / 2);
                       float lessY = (float) ((changeY1) / 2 + (changeY2) / 2);
                       setSelfPivot(-lessX, -lessY);
                       Log.d(TAG, "此时为滑动");
                   }
                   //缩放处理
                   moveDist = spacing(event);
                   double space = moveDist - oldDist;
                   float scale = (float) (getScaleX() + space / v.getWidth());
                   if (scale < SCALE_MIN) {
                       setScale(SCALE_MIN);
                   } else if (scale > SCALE_MAX) {
                       setScale(SCALE_MAX);
                   } else {
                       setScale(scale);
                   }
               }
               break;

间距计算

    /**
     * 计算两个点的距离
     *
     * @param event
     * @return
     */
    private double spacing(MotionEvent event) {
        if (event.getPointerCount() == 2) {
            float x = event.getX(0) - event.getX(1);
            float y = event.getY(0) - event.getY(1);
            return Math.sqrt(x * x + y * y);
        } else {
            return 0;
        }
    }

平移

    /**
     * 平移画面,当画面的宽或高大于屏幕宽高时,调用此方法进行平移
     *
     * @param x
     * @param y
     */
    public void setPivot(float x, float y) {
        setPivotX(x);
        setPivotY(y);
    }v

平移加上屏幕边界处理

    /**
     * 移动
     *
     * @param lessX
     * @param lessY
     */
    private void setSelfPivot(float lessX, float lessY) {
        float setPivotX = 0;
        float setPivotY = 0;
        setPivotX = getPivotX() + lessX;
        setPivotY = getPivotY() + lessY;
        if (setPivotX < 0 && setPivotY < 0) {
            setPivotX = 0;
            setPivotY = 0;
        } else if (setPivotX > 0 && setPivotY < 0) {
            setPivotY = 0;
            if (setPivotX > getWidth()) {
                setPivotX = getWidth();
            }
        } else if (setPivotX < 0 && setPivotY > 0) {
            setPivotX = 0;
            if (setPivotY > getHeight()) {
                setPivotY = getHeight();
            }
        } else {
            if (setPivotX > getWidth()) {
                setPivotX = getWidth();
            }
            if (setPivotY > getHeight()) {
                setPivotY = getHeight();
            }
        }
        setPivot(setPivotX, setPivotY);
    }

碰到的问题:

最初构思的时候,走进了个误区,以为缩放和拖拽必须二选一,于是出现很多的计算判断用户到底是缩放还是拖拽,然后相应处理,然而无论怎么计算,发现都有瑕疵(体现在:滑动时候出现缩放,缩放时有时候又夹杂滑动,导致感觉不流畅),最后发现其实根本无需如此,二者完全可以共存,而且体验完全流畅.

最后上代码: https://github.com/androidsihai1/ScaleDemo

你可能感兴趣的:(android双指缩放和双指拖拽控件)