Entrada por seletor giratório no Wear

Alguns dispositivos Wear OS são compatíveis com entrada por seletor giratório, como um botão lateral giratório (RSB). Quando o usuário gira o botão, a visualização do app precisa rolar para cima ou para baixo.

Se você usa ScrollView, ListView, HorizontalScrollView ou WearableRecyclerView, a visualização do seu app é compatível com a entrada por seletor giratório por padrão. Se você estiver usando visualizações personalizadas diferentes dessas listadas ou se quiser gerenciar manualmente eventos de entrada por seletor giratório, consulte Adicionar rolagem personalizada de entrada por seletor giratório.

Confira os seguintes recursos relacionados:

Práticas recomendadas de foco

Para responder a eventos de entrada por seletor giratório, sua visualização de rolagem precisa estar em foco. Na maioria dos casos, isso acontece automaticamente. A visualização de rolagem é focada imediatamente depois que você cria a Activity. No entanto, há situações em que é necessário gerenciar manualmente o foco da visualização do app, como:

  • Se a visualização rolável for anexada depois de Activity.onCreate () (por exemplo, se você esperar que uma solicitação de rede seja concluída antes de criar sua IU), será necessário chamar requestFocus depois de anexá-la.
  • Se a visualização rolável for inicialmente INVISIBLE ou GONE, você precisará chamar requestFocus ao configurá-la como VISIBLE.
  • Se a Activity contiver várias visualizações roláveis (por exemplo, se você estiver usando a rolagem aninhada), você precisará escolher uma para focalizar (geralmente por meio da tag <requestFocus />). A rolagem aninhada não é compatível com a rolagem RSB no momento.
  • Se a IU contiver alguma outra visualização que roube o foco quando o usuário interagir com ela (elas são raras, o exemplo mais comum é um InputText), você precisará fornecer ao usuário alguma maneira de restaurar o foco para a visualização rolável caso ele o perca. Geralmente isso é feito ouvindo os toques na visualização rolável e chamando requestFocus em resposta.

Adicionar rolagem personalizada de entrada por seletor giratório

Se a visualização rolável não for nativamente compatível com a rolagem de entrada por seletor giratório ou se você quiser fazer algo diferente de rolar em resposta a eventos de entrada por seletor giratório (como aumentar/diminuir zoom, girar discos etc.), poderá usar os métodos RotaryEncoder na Biblioteca de Suporte de Wearables.

O snippet de código a seguir mostra como usar RotaryEncoder para adicionar rolagem personalizada à visualização do app:

Kotlin

    myView.setOnGenericMotionListener(View.OnGenericMotionListener { v, ev ->
        if (ev.action == MotionEvent.ACTION_SCROLL && RotaryEncoder.isFromRotaryEncoder(ev)) {
            // Don't forget the negation here
            val delta = -RotaryEncoder.getRotaryAxisValue(ev) *
                    RotaryEncoder.getScaledScrollFactor(context)

            // Swap these axes if you want to do horizontal scrolling instead
            v.scrollBy(0, Math.round(delta))

            return@OnGenericMotionListener true
        }

        false
    })
    

Java

    myView.setOnGenericMotionListener(new View.OnGenericMotionListener() {
        @Override
        public boolean onGenericMotion(View v, MotionEvent ev) {
            if (ev.getAction() == MotionEvent.ACTION_SCROLL && RotaryEncoder.isFromRotaryEncoder(ev)) {
                // Don't forget the negation here
                float delta = -RotaryEncoder.getRotaryAxisValue(ev) * RotaryEncoder.getScaledScrollFactor(
                getContext());

                // Swap these axes if you want to do horizontal scrolling instead
                v.scrollBy(0, Math.round(delta));

                return true;
            }

            return false;
        }
    });
    

Testar o botão de entrada por seletor giratório no emulador

Você pode usar o emulador do Android para simular a rolagem de entrada por seletor giratório em um dispositivo Wear. Inicie o app Wear no emulador ao executar seu projeto ou arraste um arquivo APK para o emulador para instalá-lo.

Para testar a entrada por seletor giratório no emulador:

  1. No SDK Manager, use a guia SDK Tools para instalar o Android Emulator 26.0.3 ou posterior.
  2. Crie um AVD (Android Virtual Device) com a API 25.

    No Studio, selecione Tools > Android > AVD Manager. Crie um novo dispositivo Wear com a API 25.

  3. Execute o emulador no Android Studio.
  4. Teste a rolagem de entrada por seletor giratório.

    Clique no botão flutuante (três pontos na parte inferior da barra de ferramentas do emulador). Clique na guia Rotary input na nova janela para abrir a interface da entrada por seletor giratório.

O vídeo a seguir mostra a entrada por seletor giratório no emulador:

Dicas de comportamento de foco

  • Uma visualização é focalizável se tem a configuração setFocusableInTouchMode(true). Por padrão, isso é verdadeiro apenas para visualizações roláveis (por exemplo, ScrollView) e para InputText.
  • Por padrão, tocar em uma visualização não coloca o foco nela (mesmo que ela seja focalizável). Para alcançar esse comportamento, a visualização deve ouvir eventos de toque e chamar manualmente View.requestFocus().
  • Imediatamente após a criação de uma Activity, ela focaliza automaticamente a primeira visualização focalizável que encontra na hierarquia de visualização. Se você tem várias visualizações focalizáveis na sua Activity, essa pode não ser a desejada. É possível focalizar uma visualização diferente usando a tag <requestFocus /> (ou chamando View.requestFocus manualmente em Activity.onResume).
  • Uma visualização focalizável não é focalizada automaticamente se for anexada ou exibida após uma Activity ter sido criada, mesmo que não haja uma visualização focada no momento. Nesse caso, você precisa chamar manualmente View.requestFocus.
  • Os eventos de entrada por seletor giratório são enviados apenas para a visualização em foco. Esses eventos não aparecem na hierarquia de visualização. Se não houver uma visualização em foco ou se a visualização focalizada retornar "false" de View.onGenericMotionEvent, então (e somente então) o evento será enviado para Activity.onGenericMotionEvent.