En Wear OS 7 (nivel de API 37) y versiones posteriores, un framework de gestos con una mano, junto con una API que forma parte de Compose para Wear OS, permite a los usuarios interactuar con tu app sin tocarla.
Si bien inicialmente se admitía en dispositivos Pixel Watch (Pixel Watch 3 y modelos posteriores), el framework está disponible para todos los OEM. Si adoptas esta API, la compatibilidad con gestos de tu app se ajustará automáticamente en todo el ecosistema a medida que se expanda la compatibilidad con hardware.
Para ayudar a los usuarios a descubrir los gestos disponibles sin sobrecargar la IU, el framework de Wear OS proporciona indicadores de gestos animados. Estas sugerencias visuales destacan dónde se puede realizar un gesto, mientras que el sistema administra automáticamente su cadencia de visualización y frecuencia de silenciamiento según las preferencias del usuario.
Gestos y acciones compatibles
El framework de gestos de Wear OS admite dos tipos de gestos:
- Acción principal (doble pellizco): Se asigna a la acción principal en una pantalla, como responder una llamada o activar o desactivar la reproducción de contenido multimedia.
- Acción de descartar (giro de muñeca): Se asigna a la navegación hacia atrás, a descartar un diálogo o a cancelar un mensaje.
Cómo configurar gestos en Compose
Si bien la API de gestos con una mano puede mejorar tu IU, es importante tener en cuenta que algunos OEMs y hardware no admiten estos gestos. Si la API detecta que tu app se ejecuta en uno de estos dispositivos no admitidos, la biblioteca no realiza ninguna operación automáticamente sin afectar las interacciones táctiles estándar.
Al igual que con los comportamientos estándar de Compose, puedes habilitar los gestos con una mano en los elementos de la IU con modificadores. Configuras los gestos de tu app según la acción que se realizará (primaria o de descarte) y un gestureId para coordinar las preferencias del usuario a nivel del sistema, como la cadencia de visualización de sugerencias y el silenciamiento de frecuencia. Para expresar esta configuración, crea un objeto OneHandedGestureConfiguration. Te recomendamos que uses la función rememberOneHandedGestureConfiguration para crearlo. En OneHandedGestureConfiguration, también puedes proporcionar la prioridad del gesto.
La función rememberOneHandedGestureConfiguration hace un seguimiento del historial de interacción del usuario en las recomposiciones sin exponer el estado de la aplicación. Una vez que tu app haya creado la configuración, debe pasarla a Modifier.oneHandedGesture en tu elemento componible interactivo.
Para ayudar a los usuarios a descubrir los gestos disponibles, la biblioteca proporciona el método OneHandedGestureClickIndicator. Este método actúa como un wrapper que reemplaza su contenido subyacente para indicarle al usuario que hay disponible una acción de gesto.
Componentes interactivos
Para habilitar gestos en un control interactivo, como un botón, crea una configuración que especifique OneHandedGestureAction.Primary y aplica el modificador oneHandedGesture. Pasa el mismo MutableInteractionSource al control y al modificador para que los eventos de gestos emitan comentarios visuales de presión en el control.
Para habilitar el indicador de gestos, crea y recuerda una instancia de OneHandedGestureClickIndicatorState. Luego, para activar la respuesta visual, llama a showIndicator dentro de la devolución de llamada onGestureAvailable proporcionada por el modificador oneHandedGesture, que indica al sistema que se produjo un evento de indicación. Una vez que se llama, el componente reemplaza brevemente su contenido normal por una animación de gesto.
var isPlaying by remember { mutableStateOf(false) } val onClick = { isPlaying = !isPlaying } val gestureConfig = rememberOneHandedGestureConfiguration( action = OneHandedGestureAction.Primary ) val indicatorState = remember { OneHandedGestureClickIndicatorState() } val coroutineScope = rememberCoroutineScope() val interactionSource = remember { MutableInteractionSource() } Button( onClick = onClick, interactionSource = interactionSource, modifier = Modifier .fillMaxWidth() .oneHandedGesture( gestureConfiguration = gestureConfig, interactionSource = interactionSource, onGestureLabel = if (isPlaying) "pause" else "play", onGestureAvailable = { coroutineScope.launch { indicatorState.showIndicator() } }, onGesture = onClick ) ) { OneHandedGestureClickIndicator( gestureConfiguration = gestureConfig, state = indicatorState ) { Text(if (isPlaying) "Pause" else "Play", modifier = Modifier.fillMaxWidth()) } }
Contenedores desplazables
Para las pantallas o listas desplazables, crea una configuración que especifique OneHandedGestureAction.Primary y aplica el modificador oneHandedGesture a tu contenedor, llamando a un asistente de desplazamiento, como scrollDown.
Para proporcionar comentarios visuales sobre las acciones de desplazamiento, puedes usar OneHandedGestureScrollIndicator. Este componente funciona como un indicador de desplazamiento estándar que muestra la posición de desplazamiento, pero también puede indicar que hay un gesto de desplazamiento disponible para el usuario. Por lo general, este indicador se pasa a la ranura scrollIndicator de un ScreenScaffold y se vincula con el estado de un contenedor desplazable, como un TransformingLazyColumn. También observa un OneHandedGestureScrollIndicatorState para administrar sus transiciones visuales.
Para activar la respuesta visual, llama a showIndicator en este estado, por lo general, dentro de la devolución de llamada onGestureAvailable del modificador oneHandedGesture.
Una vez que se activa, el indicador reemplaza temporalmente su estado visual estándar por una secuencia de animación de gestos para alertar al usuario.
val scrollState = rememberTransformingLazyColumnState() val gestureConfig = rememberOneHandedGestureConfiguration( action = OneHandedGestureAction.Primary, priority = OneHandedGesturePriority.Scrollable ) val indicatorState = remember(gestureConfig) { OneHandedGestureScrollIndicatorState() } val coroutineScope = rememberCoroutineScope() ScreenScaffold( scrollState = scrollState, scrollIndicator = { OneHandedGestureScrollIndicator( gestureConfiguration = gestureConfig, indicatorState = indicatorState, scrollState = scrollState, modifier = Modifier.align(Alignment.CenterEnd) ) } ) { contentPadding -> TransformingLazyColumn( state = scrollState, contentPadding = contentPadding, modifier = Modifier .fillMaxSize() .oneHandedGesture( gestureConfiguration = gestureConfig, onGestureLabel = "scroll", onGestureAvailable = { coroutineScope.launch { indicatorState.showIndicator() } }, onGesture = { OneHandedGestureDefaults.scrollDown(scrollState) } ) ) { items(10) { index -> Text("Item $index", modifier = Modifier.padding(8.dp)) } } }
Cómo combinar varios gestos
Puedes configurar un gesto de desplazamiento y un gesto de clic con la misma acción principal agregando gesturePriority a tu objeto OneHandedGestureConfiguration:
OneHandedGesturePriority.Clickable(más alta): Se asigna a los controles interactivos, como los que tienen el tipoButtonoCard, para que capturen gestos cuando estén visibles en la pantalla.OneHandedGesturePriority.Scrollable(medio): Asigna a contenedores desplazables o paginables para que cedan a elementos secundarios en los que se puede hacer clic, pero se desplacen cuando no se vea ningún control en el que se pueda hacer clic.OneHandedGesturePriority.Unspecified(más baja): Es una prioridad sin asignar. Este es el valor predeterminado para un gesto que no tiene unpriorityestablecido.
Si se configura de forma explícita priority = OneHandedGesturePriority.Clickable en un botón interno y priority = OneHandedGesturePriority.Scrollable en su lista principal, el sistema puede mostrar este comportamiento de prioridad de gestos.
Cuando el usuario activa la acción principal con el gesto de una mano, primero se desplaza la lista hacia abajo hasta que se ve el botón y, luego, se captura la acción de clic del botón.
Cómo probar y depurar gestos con ADB
Puedes probar los gestos con una mano en un dispositivo físico o en un emulador sin realizar movimientos físicos de la muñeca con Android Debug Bridge (adb) y el servicio del sistema IWearGestureService.
Habilita la simulación de gestos
Antes de simular gestos con ADB, configura la configuración del dispositivo y las anulaciones de restricciones:
Verifica que tu dispositivo Wear OS ejecute Wear OS 7 (nivel de API 37) o una versión posterior:
adb shell getprop ro.build.version.sdkSi realizas pruebas en un dispositivo físico que no está en tu muñeca o que está en un cargador, anula la restricción de fuera del cuerpo para que el framework de gestos permanezca activo:
adb shell cmd IWearGestureService override-constraints offbody-state
Cómo activar eventos de gestos con ADB
Para simular el gesto de pellizcar dos veces (que es la acción Primary en los relojes Pixel), ejecuta el siguiente comando de shell de ADB:
adb shell cmd IWearGestureService gesture DoublePinch
Para simular el gesto de giro de muñeca (que es la acción Dismiss en los relojes Pixel), ejecuta el siguiente comando de shell de ADB:
adb shell cmd IWearGestureService gesture WristTurn
Cómo restablecer el seguimiento de sugerencias de gestos
El sistema hace un seguimiento del historial de interacción del usuario y muestra sugerencias de gestos flotantes según el parámetro de configuración de cadencia global (como Siempre o Diariamente). Cuando depures los indicadores de gestos de tu app, restablece este historial de seguimiento para que vuelvan a aparecer las sugerencias de tu paquete:
En compilaciones o emuladores de
userdebug:adb shell cmd IWearGestureService hint clear <your_package_name>En compilaciones de venta minorista (
user):En los dispositivos comerciales sin acceso de administrador,
hint clearestá bloqueado por los permisos del sistema. Borra los datos locales de la app para restablecer el descubrimiento de sugerencias:adb shell pm clear <your_package_name>
Restablece las restricciones predeterminadas
Para restablecer todas las anulaciones de restricciones de depuración cuando termines de realizar las pruebas, haz lo siguiente:
adb shell cmd IWearGestureService override-constraints reset
Soluciona problemas relacionados con la inyección de gestos
Si tu app no recibe gestos simulados, haz lo siguiente:
Verifica que la pantalla del reloj esté activa y ENCENDIDA. El framework de gestos no envía gestos a las aplicaciones mientras la pantalla está apagada o en modo ambiente. Para activar la pantalla con ADB, ejecuta lo siguiente:
adb shell input keyevent KEYCODE_WAKEUPComprueba si tu app está registrada como suscriptora de gestos activa y si actualmente tiene el enfoque de la ventana:
adb shell cmd IWearGestureService get-active-gestures -readableCuando la pantalla de gestos de tu app está en primer plano y la pantalla está activa, este comando devuelve
[DoublePinch]o[DoublePinch, WristTurn]. Si se devuelve una lista vacía ([]), verifica si la ventana tiene el enfoque o si las restricciones fuera del cuerpo bloquean la activación.Inspecciona el estado del servicio de gestos interno y los tokens de suscriptor activos:
adb shell dumpsys IWearGestureService
Recursos adicionales
Para obtener orientación sobre el diseño de cuándo y dónde usar gestos con una mano, consulta Gestos con una mano.
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Guía de diseño de gestos con una mano