处理多点触控手势

试用 Compose 方式
Jetpack Compose 是推荐在 Android 设备上使用的界面工具包。了解如何在 Compose 中使用触控和输入功能。
<ph type="x-smartling-placeholder"></ph> 多点触控手势 →

多点触控手势是指用多个指针(手指)点按屏幕 。本文档介绍了如何检测涉及 多个指针

跟踪多个指针

当多个指针同时点按屏幕时,系统会生成 以下触摸事件:

  • ACTION_DOWN: 在第一个指针点按屏幕时发送。这是手势的起点。通过 此指针的指针数据始终位于0 MotionEvent
  • ACTION_POINTER_DOWN: 当额外的指针在第一个指针之后进入屏幕时发送。您可以获取 使用 getActionIndex()
  • ACTION_MOVE: 当手势发生更改时发送, 指针。
  • ACTION_POINTER_UP: 当非主要指针抬起时发送。您可以从 刚刚使用 getActionIndex() 抬起的指针。
  • ACTION_UP: 当最后一个指针离开屏幕时发送。
  • ACTION_CANCEL: 表示已取消整个手势,包括所有指针。

开始和结束手势

手势是以 ACTION_DOWN 开头的一系列事件 事件,并以 ACTION_UPACTION_CANCEL 事件。一次只能使用一个手势。通过 向下、移动、向上和取消操作都会应用于整个手势。例如, 包含 ACTION_MOVE 的事件可以指示所有指针的移动

跟踪指针

使用指针的索引和 ID 跟踪各个指针 MotionEvent 内的位置。

  • 索引MotionEvent 存储指针 信息。指针的索引就是 数组。大多数 MotionEvent 方法将指针索引视为 参数,而不是指针 ID。
  • ID:每个指针还具有一个 ID 映射,该映射始终保持 在触摸事件之间保持不变,以便跟踪单个指针

各个指针在动作事件中以不确定的顺序出现。因此, 不同事件之间的指针索引可能会发生变化,但指针 ID 只要指针仍保持固定状态, 活动状态。使用 getPointerId() 方法获取指针的 ID,以便在所有后续活动中跟踪指针 手势中的动作事件。然后,对于连续动作事件,请使用 findPointerIndex() 方法获取给定触控点 ID 在相应动作事件中的触控点索引。 例如:

Kotlin

private var mActivePointerId: Int = 0

override fun onTouchEvent(event: MotionEvent): Boolean {
    ...
    // Get the pointer ID.
    mActivePointerId = event.getPointerId(0)

    // ... Many touch events later...

    // Use the pointer ID to find the index of the active pointer
    // and fetch its position.
    val (x: Float, y: Float) = event.findPointerIndex(mActivePointerId).let { pointerIndex ->
        // Get the pointer's current position.
        event.getX(pointerIndex) to event.getY(pointerIndex)
    }
    ...
}

Java

private int mActivePointerId;

public boolean onTouchEvent(MotionEvent event) {
    ...
    // Get the pointer ID.
    mActivePointerId = event.getPointerId(0);

    // ... Many touch events later...

    // Use the pointer ID to find the index of the active pointer
    // and fetch its position.
    int pointerIndex = event.findPointerIndex(mActivePointerId);
    // Get the pointer's current position.
    float x = event.getX(pointerIndex);
    float y = event.getY(pointerIndex);
    ...
}

如需支持多个触摸指针,您可以使用以下代码缓存所有活动指针: 其个人 ACTION_POINTER_DOWN 处的身份证件资料 ACTION_DOWN事件时间。从以下位置从缓存中移除指针: 其 ACTION_POINTER_UPACTION_UP 事件。您可能会 您会发现这些缓存的 ID 有助于正确处理其他操作事件。对于 例如,在处理 ACTION_MOVE 事件时,查找 每个缓存的活动指针 ID,则使用 getX()getY() 函数,然后将这些坐标与缓存的坐标进行比较, 看看哪些指针移动了

getActionIndex() 函数与 ACTION_POINTER_UPACTION_POINTER_DOWN事件 。请勿将此函数与 ACTION_MOVE 事件一起使用,因为 始终返回 0

检索 MotionEvent 操作

使用 getActionMasked() 方法或兼容版本 MotionEventCompat.getActionMasked() 用于检索 MotionEvent 的操作。与之前的 getAction() 方法,getActionMasked() 旨在与多种 指针。它会返回没有指针索引的操作。对于包含 有效的触控点索引,使用 getActionIndex() 可返回 与操作关联的指针,如以下代码段所示:

<ph type="x-smartling-placeholder">

Kotlin

val (xPos: Int, yPos: Int) = MotionEventCompat.getActionMasked(event).let { action ->
    Log.d(DEBUG_TAG, "The action is ${actionToString(action)}")
    // Get the index of the pointer associated with the action.
    MotionEventCompat.getActionIndex(event).let { index ->
        // The coordinates of the current screen contact, relative to
        // the responding View or Activity.
        MotionEventCompat.getX(event, index).toInt() to MotionEventCompat.getY(event, index).toInt()
    }
}

if (event.pointerCount > 1) {
    Log.d(DEBUG_TAG, "Multitouch event")

} else {
    // Single touch event.
    Log.d(DEBUG_TAG, "Single touch event")
}

...

// Given an action int, returns a string description.
fun actionToString(action: Int): String {
    return when (action) {
        MotionEvent.ACTION_DOWN -> "Down"
        MotionEvent.ACTION_MOVE -> "Move"
        MotionEvent.ACTION_POINTER_DOWN -> "Pointer Down"
        MotionEvent.ACTION_UP -> "Up"
        MotionEvent.ACTION_POINTER_UP -> "Pointer Up"
        MotionEvent.ACTION_OUTSIDE -> "Outside"
        MotionEvent.ACTION_CANCEL -> "Cancel"
        else -> ""
    }
}

Java

int action = MotionEventCompat.getActionMasked(event);
// Get the index of the pointer associated with the action.
int index = MotionEventCompat.getActionIndex(event);
int xPos = -1;
int yPos = -1;

Log.d(DEBUG_TAG,"The action is " + actionToString(action));

if (event.getPointerCount() > 1) {
    Log.d(DEBUG_TAG,"Multitouch event");
    // The coordinates of the current screen contact, relative to
    // the responding View or Activity.
    xPos = (int)MotionEventCompat.getX(event, index);
    yPos = (int)MotionEventCompat.getY(event, index);

} else {
    // Single touch event.
    Log.d(DEBUG_TAG,"Single touch event");
    xPos = (int)MotionEventCompat.getX(event, index);
    yPos = (int)MotionEventCompat.getY(event, index);
}
...

// Given an action int, returns a string description
public static String actionToString(int action) {
    switch (action) {

        case MotionEvent.ACTION_DOWN: return "Down";
	case MotionEvent.ACTION_MOVE: return "Move";
	case MotionEvent.ACTION_POINTER_DOWN: return "Pointer Down";
	case MotionEvent.ACTION_UP: return "Up";
	case MotionEvent.ACTION_POINTER_UP: return "Pointer Up";
	case MotionEvent.ACTION_OUTSIDE: return "Outside";
	case MotionEvent.ACTION_CANCEL: return "Cancel";
    }
    return "";
}
<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
图 1.多点触控绘图

其他资源

如需详细了解输入事件,请参阅以下内容 参考: