Usar gestos de pulso no Wear

Os gestos de pulso permitem interações rápidas com o app usando uma mão só quando não há tela sensível ao toque.

Por exemplo, o usuário pode rolar a tela de notificações com uma mão enquanto segura um copo de água com a outra. Outros casos de uso para gestos de pulso incluem:

  • Em um app de corrida, navegar pelas telas verticais que mostram o número de passos, o tempo decorrido e o ritmo atual.
  • Em um app de viagens, rolar a tela para conferir informações sobre o voo e portão de embarque.
  • Em um app de notícias, rolar a tela para ler artigos.

Para testar os gestos de pulso de um relógio, confira se os gestos estão ativados em Configurações > Recursos avançados > Gestos > Gestos de pulso ativados. Em seguida, selecione Iniciar tutorial para concluir o tutorial sobre gestos no relógio.

Observação: balançar o pulso aciona a ação "voltar" ou "desfazer" em todo o sistema. Esse gesto não pode ser personalizado de acordo com o app.

Os gestos de pulso podem ser usados das maneiras apresentadas abaixo, conforme descrito neste guia:

Cada gesto de pulso é mapeado para uma constante int da classe KeyEvent, conforme mostrado na tabela a seguir:

Gesto Evento de tecla Descrição
Virar o pulso para fora KEYCODE_NAVIGATE_NEXT Esse código de tecla vai para o próximo item.
Virar o pulso para dentro KEYCODE_NAVIGATE_PREVIOUS Esse código de tecla vai para o item anterior.

Usar um layout curvo para compatibilidade com gestos de pulso

A classe WearableRecyclerView inclui um layout em curva para listas e oferece suporte a gestos de pulso automaticamente. Ela tem ações predefinidas para gestos de pulso realizados quando a visualização está em foco. Para mais informações sobre como usar a classe WearableRecyclerView, consulte Criar listas no Wear OS. Consulte também a seção Práticas recomendadas deste guia.

Observação:a classe WearableRecyclerView substitui uma classe semelhante, que foi descontinuada na Biblioteca de Suporte de Wearables.

Mesmo que você use uma WearableRecyclerView, recomendamos utilizar constantes da classe KeyEvent. As ações predefinidas podem ser substituídas criando uma subclasse para WearableRecyclerView e implementando o callback onKeyDown() novamente. Esse comportamento pode ser totalmente desativado usando setEnableGestureNavigation(false). Para mais informações, consulte Processar ações do teclado.

Usar eventos de teclas diretamente

Você pode usar eventos de teclas fora de uma WearableRecyclerView para acionar novas ações em resposta a eventos de gesto. É importante ressaltar que esses eventos de gestos são reconhecidos quando o dispositivo está no modo ativo e são entregues da mesma forma que todos os eventos de tecla.

Uma classe que responde à interação do usuário, como uma View ou uma Activity, que implementa KeyEvent.Callback, pode ouvir eventos associados a gestos de pulso, assim como qualquer outro evento de tecla. O framework do Android chama a View ou a Activity em foco quando ocorre um evento de tecla. No caso de gestos, o callback do método onKeyDown() é chamado.

Por exemplo, um app pode modificar ações predefinidas em uma View ou Activity que implemente KeyEvent.Callback desta forma:

Kotlin

class GesturesActivity : Activity() {

    /* KeyEvent.Callback */
    override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
        return when (keyCode) {
            KeyEvent.KEYCODE_NAVIGATE_NEXT ->
                // Do something that advances a user View to the next item in an ordered list.
                moveToNextItem()
            KeyEvent.KEYCODE_NAVIGATE_PREVIOUS ->
                // Do something that advances a user View to the previous item in an ordered list.
                moveToPreviousItem()
            else -> {
                // If you did not handle it, let it be handled by the next possible element as determined
                // by the Activity.
                super.onKeyDown(keyCode, event)
            }
        }
    }

    /** Shows the next item in the custom list.  */
    private fun moveToNextItem(): Boolean {
        ...
        // Return true if handled successfully, otherwise return false.
        return false
    }

    /** Shows the previous item in the custom list.  */
    private fun moveToPreviousItem(): Boolean {
        ...
        // Return true if handled successfully, otherwise return false.
        return false
    }
}

Java

public final class GesturesActivity extends Activity {

 @Override /* KeyEvent.Callback */
 public boolean onKeyDown(int keyCode, KeyEvent event) {
  switch (keyCode) {
   case KeyEvent.KEYCODE_NAVIGATE_NEXT:
    // Do something that advances a user View to the next item in an ordered list.
    return moveToNextItem();
   case KeyEvent.KEYCODE_NAVIGATE_PREVIOUS:
    // Do something that advances a user View to the previous item in an ordered list.
    return moveToPreviousItem();
  }
  // If you did not handle it, let it be handled by the next possible element as determined by the Activity.
  return super.onKeyDown(keyCode, event);
 }

 /** Shows the next item in the custom list. */
 private boolean moveToNextItem() {
  boolean handled = false;
  ...
  // Return true if handled successfully, otherwise return false.
  return handled;
 }

 /** Shows the previous item in the custom list. */
 private boolean moveToPreviousItem() {
  boolean handled = false;
  ...
  // Return true if handled successfully, otherwise return false.
  return handled;
 }
}

Práticas recomendadas

  • Revise as páginas KeyEvent e KeyEvent.Callback para entender como funciona a entrega de eventos de teclas para View e Activity.
  • Mantenha uma affordance direcional consistente: use "virar o pulso para fora" para avançar e "virar o pulso para dentro" para voltar.
  • Tenha um toque paralelo para um gesto.
  • Forneça feedback visual.
  • Não use códigos de tecla para implementar funcionalidades que não sejam intuitivas em relação ao resto do sistema. Por exemplo, não use KEYCODE_NAVIGATE_NEXT para cancelar uma ação ou navegar de um lado para o outro com movimentos de pulso.
  • Elementos que não estão mostrados na interface do usuário, como visualizações fora da tela ou parcialmente cobertas, não podem interceptar os eventos de tecla. O mesmo vale para qualquer evento de tecla.
  • Não reinterprete movimentos de pulso repetidos como um novo gesto. Isso pode entrar em conflito com o gesto "balançar o pulso" do sistema.
  • Para que uma visualização receba eventos de tecla de gestos, ela precisa estar em foco. Consulte View.setFocusable().

    Como os gestos são tratados como eventos de tecla, eles acionam uma transição que sai do "modo de toque" e, por isso, podem iniciar ações inesperadas. Como os usuários podem alternar entre toques e gestos, pode ser necessário usar o método View::setFocusableInTouchmode(). Em alguns casos, também pode ser necessário usar setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS) para que, quando o foco mudar ao entrar ou sair do "modo de toque", a visualização volte para o foco.

  • Use requestFocus() e clearFocus() com cuidado:
    • Ao chamar requestFocus(), confira se a visualização pode ser colocada em foco. Se ela estiver fora da tela ou coberta por outra, podem ocorrer surpresas quando os gestos acionarem os callbacks.
    • O clearFocus() inicia uma pesquisa de foco para encontrar outra visualização adequada. Dependendo da hierarquia da visualização, essa pesquisa pode exigir um nível de programação mais avançado. Ela também pode acabar atribuindo foco a uma visualização inesperada.
  • Os eventos de tecla são mostrados primeiro na visualização em foco na hierarquia. Se a visualização em foco não processar o evento (ou seja, retornar false), ele não será entregue à visualização mãe, mesmo que possa receber foco e tenha um KeyListener. Em vez disso, o evento será entregue à atividade atual, mantendo a hierarquia de visualização em foco.

    Pode ser necessário capturar todos os eventos de nível mais alto e, em seguida, transmitir os códigos relevantes. Como alternativa, você pode criar uma subclasse para a atividade e modificar o método dispatchKeyEvent(KeyEvent event) para interceptar as teclas quando necessário ou processar os eventos de tecla quando isso não ocorrer em níveis mais baixos.