Rejeição da palma ao usar a stylus

Ícone de classificação de cinco estrelas

Uma stylus pode ser uma ferramenta muito produtiva e criativa. No entanto, quando os usuários desenham, escrevem ou interagem com o app usando uma stylus, às vezes eles tocam na tela com a palma da mão. O evento de toque pode ser informado ao app antes que o sistema reconheça e desconsidere o evento como um toque acidental da palma da mão.

Práticas recomendadas

O app precisa identificar e ignorar eventos de toque irrelevantes. No Jetpack Compose, é possível acessar o Android subjacente MotionEvent de um PointerEvent. Verifique o MotionEvent para ACTION_CANCEL, que indica que um gesto precisa ser interrompido e pode precisar ser revertido. No Android 13 (nível 33 da API) e versões mais recentes, verifique a FLAG_CANCELED flag nos ACTION_CANCEL e ACTION_POINTER_UP eventos, que fornece um sinal forte de que o toque foi não intencional, como um toque da palma da mão.

Ingredientes

  • Modifier.pointerInput(): o modificador do Compose usado para processar a entrada do ponteiro.
  • PointerEvent: representa um evento de ponteiro no Compose, que contém uma ou mais mudanças.
  • PointerEvent.motionEvent: propriedade de extensão que fornece acesso ao MotionEvent do Android subjacente (aceita valores nulos).
  • MotionEvent: representa eventos de toque e movimento. Contém as informações necessárias para determinar se um evento será desconsiderado ou não.
  • ACTION_CANCEL: constante MotionEvent que indica que um gesto foi cancelado. O gesto precisa ser interrompido e pode precisar ser revertido.
  • ACTION_POINTER_UP: constante MotionEvent que indica que um ponteiro diferente do primeiro foi levantado, ou seja, parou de fazer contato com a tela do dispositivo.
  • FLAG_CANCELED: constante MotionEvent que indica que o ponteiro que foi levantado causou um evento de toque não intencional. Adicionado aos eventos ACTION_POINTER_UP e ACTION_CANCEL no Android 13 (nível 33 da API) e mais recentes.

Etapas

Examine objetos MotionEvent enviados para seu app. Use as APIs MotionEvent para determinar as características do evento:

  • Eventos de ponteiro único : procure ACTION_CANCEL, que indica que o gesto precisa ser interrompido. No Android 13 e mais recentes, procure também por FLAG_CANCELED para confirmar se o toque foi não intencional.
  • Eventos com vários ponteiros : no Android 13 e mais recentes, procure ACTION_POINTER_UP e FLAG_CANCELED para identificar toques não intencionais.

Responda a esses eventos interrompendo o gesto e revertendo todas as mudanças temporárias.

1. Obter objetos de eventos de movimento

Use Modifier.pointerInput para processar a entrada do ponteiro em um elemento combinável. No escopo de entrada do ponteiro, use awaitPointerEventScope e awaitPointerEvent para receber eventos e recuperar o MotionEvent do Android subjacente usando a propriedade 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. Determinar a ação e as flags do evento

Procure ACTION_CANCEL no MotionEvent, que indica um evento de ponteiro único em todos os níveis de API. No Android 13 e mais recentes, verifique ACTION_POINTER_UP para 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. Desfazer o gesto

Depois de identificar um toque da palma da mão, você pode desfazer os efeitos do gesto na tela.

O app precisa manter um histórico de ações do usuário para que entradas não intencionais, como toques da palma da mão, possam ser desfeitas. Consulte Implementar um app de desenho básico no Melhorar o suporte à stylus em um app Android codelab para conferir um exemplo.

Resultados

O app agora pode identificar e rejeitar toques da palma da mão em eventos de vários ponteiros no Android 13 e níveis da API mais recentes e em eventos de ponteiro único em todos os níveis da API.

Outros recursos

Para mais informações, consulte os tópicos abaixo: