Защита от случайных прикосновений при использовании стилуса

Значок рейтинга в пять звезд

Стилус может быть очень полезным инструментом для работы и творчества. Но когда пользователи рисуют, пишут или взаимодействуют с приложением с помощью стилуса, они иногда касаются экрана ладонью. Событие касания может быть передано в приложение до того, как система распознает и отклонит его как случайное касание ладонью.

Рекомендации

Приложение должно определять лишние касания и игнорировать их. В Jetpack Compose доступ к базовому Android MotionEvent можно получить из PointerEvent. Проверьте MotionEvent на наличие ACTION_CANCEL, указывающего на то, что жест должен быть остановлен и, возможно, отменен. В Android 13 (API уровня 33) и более поздних версиях проверяйте флаг FLAG_CANCELED в событиях ACTION_CANCEL и ACTION_POINTER_UP. Он указывает на то, что прикосновение было случайным, например ладонью.

Ингредиенты

  • Modifier.pointerInput() – модификатор Compose, используемый для обработки ввода указателя.
  • PointerEvent: представляет событие указателя в Compose, которое содержит одно или несколько изменений.
  • PointerEvent.motionEvent – свойство расширения, которое предоставляет доступ к базовому объекту MotionEvent Android (может иметь значение null).
  • MotionEvent – события касания и движения. Содержит информацию, необходимую для определения того, следует ли игнорировать событие.
  • ACTION_CANCEL: константа MotionEvent, указывающая, что жест был отменен. Жест должен быть остановлен и, возможно, отменен.
  • ACTION_POINTER_UP – константа MotionEvent, указывающая, что указатель, отличный от первого, был поднят (то есть перестал касаться экрана устройства).
  • FLAG_CANCELED – константа MotionEvent, указывающая, что при поднятии указателя произошло случайное событие касания. Добавлен в события ACTION_POINTER_UP и ACTION_CANCEL в Android 13 (уровень API 33) и более поздних версиях.

Шаги

Изучите объекты MotionEvent, отправленные в ваше приложение. Используйте API MotionEvent, чтобы определить характеристики события:

  • События с одним указателем. Проверьте наличие ACTION_CANCEL, которое указывает на то, что жест должен быть остановлен. На устройствах с Android 13 и более поздних версий также проверьте, есть ли на экране значок FLAG_CANCELED. Он означает, что вы коснулись экрана случайно.
  • События с несколькими указателями. В Android 13 и более поздних версий проверяйте ACTION_POINTER_UP и FLAG_CANCELED, чтобы выявлять случайные нажатия.

Чтобы отреагировать на эти события, остановите жест и отмените все временные изменения.

1. Как получить объекты событий движения

Используйте Modifier.pointerInput, чтобы обрабатывать ввод указателя в Composable. В области ввода указателя используйте awaitPointerEventScope и awaitPointerEvent, чтобы получать события, и извлекайте базовый объект Android MotionEvent с помощью свойства 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 в разделе Реализация базового приложения для рисования.

Результаты

Теперь ваше приложение может распознавать и отклонять касания ладонью для событий с несколькими указателями на устройствах с Android 13 и более поздних версий, а также для событий с одним указателем на устройствах с любым уровнем API.

Дополнительные ресурсы

Дополнительную информацию можно найти в следующих источниках: