Entrada rotativa en Wear

Algunos dispositivos Wear OS admiten entrada rotativa, como un botón lateral giratorio (RSB). Cuando el usuario gira el botón, la vista actual de la app debería desplazarse hacia arriba o hacia abajo.

Si estás utilizando ScrollView, ListView, HorizontalScrollView o WearableRecyclerView en tu app, entonces la vista ofrece compatibilidad con la entrada rotativa de forma predeterminada. Si usas otras vistas personalizadas, o si deseas controlar manualmente los eventos de entrada rotativos, consulta Cómo agregar desplazamiento de entrada rotativo personalizado.

Consulta los siguientes recursos relacionados:

Enfócate en las prácticas recomendadas

Para responder a los eventos de entrada rotativos, tu vista de desplazamiento debe estar enfocada. En la mayoría de los casos, esto sucede de forma automática; la vista de desplazamiento se enfoca inmediatamente después de que hayas creado una Actividad. Sin embargo, hay situaciones en las que es necesario controlar de forma manual el enfoque de la vista de tu app, como en estos casos:

  • Si se adjunta la vista desplazable después de Activity.onCreate() (por ejemplo, si esperas a que finalice una solicitud de red antes de diseñar la IU), debes llamar a requestFocus después de adjuntarla.
  • Si, en un principio, la vista desplazable es INVISIBLE o GONE, debes llamar a requestFocus cuando lo configures como VISIBLE.
  • Si tu Actividad contiene varias vistas desplazables (por ejemplo, si estás usando un desplazamiento anidado), debes elegir una para enfocar (generalmente a través de la etiqueta <requestFocus />). Por el momento, el desplazamiento anidado no es compatible con el desplazamiento RSB.
  • Si tu IU contiene alguna otra vista que le quita el enfoque cuando el usuario interactúa con ella (algo poco frecuente, el ejemplo más común es un InputText), debes proporcionarle al usuario alguna forma de restaurar el enfoque en la vista desplazable. Por lo general, esto se hace detectando toques en la vista desplazable y llamando a requestFocus en respuesta.

Cómo agregar desplazamiento de entrada rotativa personalizado

Si tu vista desplazable no admite de forma nativa el desplazamiento de entrada rotativa o si deseas hacer algo más que un desplazamiento en respuesta a eventos de entrada rotativa (acercar o alejar, girar diales, etc.), puedes usar los métodos de RotaryEncoder en la Biblioteca de compatibilidad con dispositivos wearables.

El siguiente fragmento de código muestra cómo usar RotaryEncoder para agregar un desplazamiento personalizado en la vista de tu 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;
        }
    });
    

Cómo probar el botón de entrada rotativa en el emulador

Puedes usar el Emulador de Android para simular el desplazamiento de entrada rotativa en un dispositivo Wear. Inicia tu app de Wear en el emulador cuando ejecutes tu proyecto o arrastra un archivo APK al emulador para instalarlo.

Para probar la entrada rotativa en el emulador, haz lo siguiente:

  1. Desde SDK Manager, usa la pestaña SDK tools para obtener Android Emulator versión 26.0.3 o posterior.
  2. Crea un AVD (dispositivo virtual de Android) con API 25.

    En Studio, selecciona Herramientas>Android>AVD Manager. Crea un nuevo dispositivo Wear con API 25.

  3. Ejecuta el emulador desde Android Studio.
  4. Intenta ejecutar el desplazamiento de entrada rotativa.

    Haz clic en el botón de contenido adicional (tres puntos ubicados en la parte inferior de la barra de herramientas del emulador). En la nueva ventana, haz clic en la pestaña Entrada rotativa para abrir la interfaz de entrada rotativa.

El siguiente video muestra la entrada rotativa en el emulador:

Sugerencias sobre el comportamiento del enfoque

  • Una vista es enfocable si tiene setFocusableInTouchMode(true). De forma predeterminada, esto solo se aplica a las vistas desplazables (por ejemplo, ScrollView) y InputText.
  • De forma predeterminada, presionar una vista no la enfoca (incluso si es enfocable). Para lograr este comportamiento, la vista debe detectar eventos de toque y llamar de forma manual a View.requestFocus().
  • Inmediatamente después de crear una Activity, enfoca de manera automática la primera vista enfocable que encuentra en su jerarquía de vistas. Si tienes varias vistas enfocables en tu Actividad, es posible que no sea la que querías. Puedes enfocar otra con la etiqueta <requestFocus /> (o llamando de forma manual a View.requestFocus en Activity.onResume).
  • Una vista enfocable no se enfoca automáticamente si está adjuntada o aparece visible después de que se haya creado una Actividad, incluso si no hay una vista enfocada en ese momento. En este caso, debes llamar de forma manual a View.requestFocus.
  • Los eventos de entrada rotativa solo se envían a la vista enfocada. Estos eventos no aparecen en la jerarquía de vistas. Si no hay una vista enfocada o si la vista enfocada muestra un valor falso desde View.onGenericMotionEvent, entonces (y solamente entonces) se envía el evento a Activity.onGenericMotionEvent.