Android 多點觸控教程

MotionEvent.getActionMaskde()

常見值有:java

  1. ACTION_DOWN 第一個手指按下(以前沒有任何手指觸摸到View)
  2. ACTION_UP 最後一個手指擡起(擡起後沒有手指觸摸View,這個手指未必是ACTION_DOWN)
  3. ACTION_MOVE 有手指所發生移動
  4. ACTION_POINTEER_DOWN 額外手指按下(按下以前已經有別的手指觸摸到View)
  5. ACTION_POINTER_UP 有手指擡起,但不是最後一個(擡起以後,仍然有別的手指在觸摸着View)

觸摸事件的結構

  1. 觸摸事件是按序列來分組的,每一組事件必然以ACTION_DOWN開頭,以ACTION_UP或ACTION_CANCEL結束
  2. ACTION_POINTER_DOWN和ACTION_MOVE同樣,只是事件序列組成部分,並不會單獨分出新的事件序列
  3. 觸摸事件序列是針對View的,而不是針對pointer的。
  4. 同一個時刻,一個View要麼沒有事件序列,要麼只有一個事件序列

多點觸控的三種類型

  1. 接力型 同一時刻只有一個pointer起做用,即最新的pointer。如listview、recyclerview。實現方式:在ACTION_POINTER_DOWN和ACTION_POINTER_UP時記錄下最新的pointer,在以後的ACTION_MOVE事件中使用這個pointer來判斷位置。
case MotionEvent.ACTION_DOWN:
            //拿到第0跟手指
            trackID = event.getPointerId(0);
            downX = event.getX();
            downY = event.getY();
            originalOffsetX = offsetX;
            originalOffsetY = offsetY;
            break;
        case MotionEvent.ACTION_MOVE:
            int index = event.findPointerIndex(trackID);
            offsetX = originalOffsetX + event.getX(index) - downX;
            offsetY = originalOffsetY + event.getY(index) - downY;
            invalidate();
            break;
        case MotionEvent.ACTION_POINTER_DOWN:
            int actionIndex = event.getActionIndex();
            trackID = event.getPointerId(actionIndex);
            downX = event.getX(actionIndex);
            downY = event.getY(actionIndex);
            originalOffsetX = offsetX;
            originalOffsetY = offsetY;
            break;

        case MotionEvent.ACTION_POINTER_UP:
            //擡起來的這根手指的index
            actionIndex = event.getActionIndex();
            int pointerId = event.getPointerId(actionIndex);
            if (pointerId == trackID) {
                //將當前的點分配到這根手指
                int newIndex;
                //若是擡起來的這根手指剛好是最後一根則
                if (actionIndex == event.getPointerCount() - 1) {
                    newIndex = event.getPointerCount() - 2;
                } else {
                    //若是是其餘手指則
                    newIndex = event.getPointerCount() - 1;
                }
                trackID = event.getPointerId(newIndex);
                downX = event.getX(newIndex);
                downY = event.getY(newIndex);
                originalOffsetX = offsetX;
                originalOffsetY = offsetY;
            }
            break;

複製代碼
  1. 配合型/協做型 全部觸摸到View的pointer共同起做用。 如:ScaleGestureDetector,以及GestureDetector的onScroll()方法判斷。實現方式:在每一個DOWN、POINTER_DOWN、POINTER_UP、UP事件中使用全部的pointer的座標來共同更新焦點座標,在MOVE事件中使用全部的pointer的座標來判斷位置。
float sumX = 0;
        float sumY = 0;
        int pointerCount = event.getPointerCount();
        boolean isPointerUp = event.getActionMasked() == MotionEvent.ACTION_POINTER_UP;
        for (int i = 0; i < pointerCount; i++) {
            if (!(isPointerUp && i == event.getActionIndex())) {
                sumX += event.getX(i);
                sumY += event.getY(i);
            }
        }
        if (isPointerUp) {
            pointerCount -= 1;
        }
        float focusX = sumX / pointerCount;
        float focusY = sumY / pointerCount;
        switch (event.getActionMasked()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_POINTER_DOWN:
            case MotionEvent.ACTION_POINTER_UP:
                downX = focusX;
                downY = focusY;
                originalOffsetX = offsetX;
                originalOffsetY = offsetY;
                break;
            case MotionEvent.ACTION_MOVE:
                offsetX = originalOffsetX + focusX - downX;
                offsetY = originalOffsetY + focusY - downY;
                invalidate();
                break;
        }
複製代碼
  1. 各自獨立型 各個pointer作不一樣的事,互不影響。典型:支持多畫筆的畫板應用。實現方式:在每一個DOWN、POINTER_DOWN事件中記錄下每一個pointer的id,在MOVE事件中使用id對他們進行追蹤。
case ACTION_DOWN:
        case ACTION_POINTER_DOWN:
            int actionIndex = event.getActionIndex();
            int pointerId = event.getPointerId(actionIndex);
            Path path = new Path();
            path.moveTo(event.getX(actionIndex), event.getY(actionIndex));
            paths.append(pointerId, path);
            invalidate();
            break;
        case ACTION_MOVE:
            for (int i = 0; i < event.getPointerCount(); i++) {
                pointerId = event.getPointerId(i);
                path = paths.get(pointerId);
                path.lineTo(event.getX(i), event.getY(i));
            }
            invalidate();
            break;
        case ACTION_UP:
        case ACTION_POINTER_UP:
            pointerId = event.getPointerId(event.getActionIndex());
            paths.remove(pointerId);
            invalidate();
            break;
複製代碼
相關文章
相關標籤/搜索