触控笔防手掌误触

五星评级图标

触控笔是一种可用于大屏设备上的极其高效、富有创造力的工具。但是,当用户使用触控笔绘图、手写或与应用互动时,有时会用手掌触摸屏幕。系统可能会在将其识别为意外手掌误触并予以忽略之前便将相应触摸事件报告给您的应用。

最佳做法

您的应用必须识别无关的触摸事件,并忽略这些事件。在 Jetpack Compose 中,您可以从 PointerEvent 访问底层 Android MotionEvent。检查 MotionEvent 是否包含 ACTION_CANCEL,这表示手势应停止,可能需要回滚。在 Android 13(API 级别 33)及更高版本中,请检查 ACTION_CANCELACTION_POINTER_UP 事件中的 FLAG_CANCELED 标志,该标志可强烈表明触摸是无意的,例如手掌触摸。

所需要素

  • Modifier.pointerInput():用于处理指针输入的 Compose 修饰符。
  • PointerEvent:表示 Compose 中的指针事件,其中包含一项或多项更改。
  • PointerEvent.motionEvent:用于提供对底层 Android MotionEvent 的访问权限的扩展属性(可为 null)。
  • MotionEvent:表示触摸和移动事件。包含确定是否应忽略某事件所需的信息。
  • ACTION_CANCELMotionEvent 常量,用于表明手势已被取消;手势应停止,并且可能需要回滚。
  • ACTION_POINTER_UPMotionEvent 常量,用于表明除第一个指针以外的某个指针已被释放(即放弃了与设备屏幕的接触)。
  • FLAG_CANCELEDMotionEvent 常量,用于表明指针释放导致了一次无意中的触摸事件。已添加到 Android 13(API 级别 33)及更高版本的 ACTION_POINTER_UPACTION_CANCEL 事件。

步骤

检查分派给您的应用的 MotionEvent 对象。使用 MotionEvent API 确定事件特征:

  • 单指针事件 - 检查是否有 ACTION_CANCEL,它表示手势应停止。在 Android 13 及更高版本中,还要检查是否有 FLAG_CANCELED,以确认触摸是无意的。
  • 多指针事件 - 在 Android 13 及更高版本中,检查是否有 ACTION_POINTER_UPFLAG_CANCELED 以识别无意触摸。

通过停止手势并回滚所有临时更改来响应这些事件。

1. 获取动作事件对象

使用 Modifier.pointerInput 处理可组合项上的指针输入。在指针输入范围内,使用 awaitPointerEventScopeawaitPointerEvent 接收事件,并使用 motionEvent 属性检索底层 Android MotionEvent

import androidx.compose.ui.input.pointer.pointerInput
    Box(
        modifier = Modifier
            .fillMaxSize()
            .pointerInput(Unit) {
                awaitPointerEventScope {
                    while (true) {
                        val event = awaitPointerEvent()
                        val motionEvent = event.motionEvent
                        if (motionEvent != null) {
                            // Process motion event.
                        }
                    }
                }
            }
    )

2. 确定事件操作和标志

检查 MotionEvent 是否有 ACTION_CANCEL,它在所有 API 级别上都用于指示单指针事件。在 Android 13 及更高版本中,检查 ACTION_POINTER_UP 中是否有 FLAG_CANCELED

import androidx.compose.ui.input.pointer.pointerInput
    Box(
        modifier = Modifier
            .fillMaxSize()
            .pointerInput(Unit) {
                awaitPointerEventScope {
                    while (true) {
                        val event = awaitPointerEvent()
                        val motionEvent = event.motionEvent ?: continue

                        when (motionEvent.actionMasked) {
                            MotionEvent.ACTION_CANCEL -> {
                                // Process canceled single-pointer motion event for all SDK versions.
                            }
                            MotionEvent.ACTION_POINTER_UP -> {
                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
                                    (motionEvent.flags and MotionEvent.FLAG_CANCELED) == MotionEvent.FLAG_CANCELED
                                ) {
                                    // Process canceled multi-pointer motion event for Android 13 and higher.
                                }
                            }
                        }
                    }
                }
            }
    )

3. 撤消手势

识别出手掌触摸后,您就可以撤消相应手势在屏幕上的效果。

您的应用必须保留用户操作历史记录,以便撤消手掌触摸等意外输入。如需查看示例,请参阅增强 Android 应用中的触控笔性能支持 Codelab 中的实现基本绘图应用

结果

现在,在 Android 13 及更高 API 级别上,您的应用可以针对多指针事件识别和拒绝手掌触摸;在所有 API 级别上,您的应用可以针对单指针事件识别和拒绝手掌触摸。

其他资源

如需了解详情,请参阅以下内容: