タッチペンのパーム リジェクション

5 つ星評価アイコン

タッチペンは、生産性と創造性に優れたツールです。しかし、ユーザーがタッチペンを使用して描画、書き込み、またはアプリの操作を行うと、手のひらが画面に触れることがあります。このタッチイベントが、手のひらでの偶発的なタッチとして認識されて無視される前に、アプリに報告される場合があります。

ベスト プラクティス

アプリは、不要なタッチイベントを識別して無視する必要があります。Jetpack Compose では、PointerEvent から基盤となる Android の MotionEvent にアクセスできます。MotionEventACTION_CANCEL を確認します。これは、ジェスチャーを停止してロールバックする必要がある可能性があることを示します。Android 13(API レベル 33)以降では、ACTION_CANCEL イベントと ACTION_POINTER_UP イベントで FLAG_CANCELED フラグを確認します。このフラグは、手のひらでのタッチなど、意図しないタッチであったことを示す強力なシグナルを提供します。

材料

  • Modifier.pointerInput(): ポインタ入力の処理に使用される Compose 修飾子。
  • PointerEvent: 1 つ以上の変更を含む Compose のポインタ イベントを表します。
  • PointerEvent.motionEvent: 基盤となる Android MotionEvent へのアクセスを提供する拡張機能プロパティ(null 可能)。
  • MotionEvent: タッチイベントと移動イベントを表します。イベントを無視するかどうかを決定するために必要な情報が含まれています。
  • ACTION_CANCEL: ジェスチャーがキャンセルされたことを示す MotionEvent 定数。ジェスチャーを停止し、ロールバックする必要がある場合があります。
  • ACTION_POINTER_UP: 最初のポインタ以外のポインタが上に移動した(つまり、デバイス画面との接続が喪失した)ことを示す MotionEvent 定数。
  • FLAG_CANCELED: ポインタの上移動により意図しないタップイベントが発生したことを示す MotionEvent 定数。Android 13(API レベル 33)以降の ACTION_POINTER_UP および ACTION_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. イベント アクションとフラグを決定する

MotionEventACTION_CANCEL を確認します。これは、すべての API レベルでのシングル ポインタ イベントを表します。Android 13 以降では、ACTION_POINTER_UPFLAG_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. 操作を元に戻す

手のひらでのタップを識別した場合、操作による画面上の効果を元に戻すことができます。

手のひらでのタップなどの意図しない入力を元に戻すには、アプリでユーザー操作の履歴を保持する必要があります。Codelab の Android アプリでのタッチペン サポートの強化基本的な描画アプリを実装するで例を紹介しています。

結果

アプリは、Android 13 以降の API レベルにおけるマルチポインタ イベントと、すべての API レベルにおけるシングルポインタ イベントで、手のひらでのタップを識別、拒否できるようになりました。

参考情報

詳しくは次の記事をご覧ください。