Cómo usar gestos de muñeca en Wear
Organiza tus páginas con colecciones
Guarda y categoriza el contenido según tus preferencias.
Cuando no es conveniente usar una pantalla táctil, los gestos de muñeca pueden permitir interacciones rápidas con una mano en tu app.
Por ejemplo, un usuario puede desplazarse por las notificaciones con una mano mientras sostiene un vaso de agua con la otra. Entre otros casos de uso de gestos de muñeca, se incluyen los siguientes:
- En una app para trotar, navegar a través de pantallas verticales que muestran los pasos dados, el tiempo transcurrido y el ritmo actual
- En una app de viajes, desplazarse por la información sobre vuelos y puertas de embarque
- En una app de noticias, desplazarse por los artículos
Para revisar los gestos de muñeca en un reloj, confirma que estén activados seleccionando Configuración > Funciones avanzadas > Gestos > Wrist Gestures On. Luego, selecciona Launch Tutorial para completar el instructivo sobre gestos en el reloj.
Nota: Agitar la muñeca representa el gesto de atrás o deshacer en todo el sistema y no está disponible para personalizar en las apps.
Los gestos de muñeca se pueden utilizar de las siguientes maneras, como se describe en esta guía:
Cada gesto de muñeca se asigna a una constante int
de la clase KeyEvent
, como se muestra en la siguiente tabla:
Usa un diseño curvo que sea compatible con los gestos de muñeca
La clase
WearableRecyclerView
proporciona un diseño curvo para las listas y admite automáticamente los gestos de muñeca. Tiene acciones predefinidas para casos de gestos de muñeca cuando la vista está enfocada. Para obtener información sobre el uso de la clase WearableRecyclerView
, consulta Cómo crear listas en Wear OS. Además, consulta la sección Prácticas recomendadas de esta guía.
Nota: La clase WearableRecyclerView
reemplaza una clase obsoleta similar en la Biblioteca de compatibilidad para wearables.
Incluso si usas una WearableRecyclerView
, es posible que quieras usar constantes de la clase KeyEvent
. Las acciones predefinidas se pueden anular dividiendo en subclases WearableRecyclerView
y volviendo a implementar la devolución de llamada onKeyDown()
. El comportamiento se puede inhabilitar por completo mediante setEnableGestureNavigation(false)
.
Para obtener más información, consulta Cómo controlar las acciones del teclado.
Cómo usar directamente eventos de tecla
Puedes usar eventos de tecla fuera de
WearableRecyclerView
para activar nuevas acciones en respuesta a eventos gestuales. Es importante destacar que estos eventos de gestos se reconocen cuando un dispositivo está en modo activo y se entregan de la misma manera que todos los eventos de tecla.
Una clase que se relaciona con la interacción del usuario, como una View
o una Activity
, y que implementa
KeyEvent.Callback
puede escuchar eventos de tecla relacionados con los gestos de muñeca de la misma manera que escucha cualquier otro evento tecla. El framework de Android llama a los objetos View
o Activity
que están enfocados con los eventos de tecla. Para los gestos, se llama a la devolución de llamada del método onKeyDown()
cuando se producen gestos.
Como ejemplo, una app puede anular acciones predefinidas en una View
o Activity
que implemente KeyEvent.Callback
de la siguiente manera:
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ácticas recomendadas
- Revisa las páginas de
KeyEvent
y
KeyEvent.Callback
para la entrega de eventos de tecla a tu View
y Activity
.
- Mantén una indicación visual direccional coherente: usa el gesto de girar la muñeca hacia afuera para ir al contenido siguiente y el de girar la muñeca hacia adentro para ir al anterior.
- Ten un toque paralelo para un gesto.
- Proporciona información visual.
- No utilices un código de tecla para implementar una funcionalidad que sea contraintuitiva para el resto del sistema. Por ejemplo, no uses
KEYCODE_NAVIGATE_NEXT
para cancelar una acción o navegar el eje de izquierda a derecha con giros de muñeca.
- No interceptes los eventos de tecla en elementos que no forman parte de la interfaz de usuario, como las vistas que están fuera de la pantalla o parcialmente cubiertas. Esto funciona de la misma manera que para cualquier evento de tecla.
- No reinterpretes los gestos de giros de muñeca repetidos como un gesto nuevo.
Esto podría entrar en conflicto con el gesto "agitar la muñeca" del sistema.
Para que una vista reciba eventos de tecla de gestos, debe estar enfocada. Consulta
View.setFocusable()
.
Debido a que los gestos se tratan como eventos de tecla, activan una transición del "modo táctil" que puede generar acciones inesperadas. Como los usuarios pueden alternar entre usar el tacto y los gestos, podría ser necesario usar el método
View::setFocusableInTouchmode()
. En algunos casos, también puede ser necesario usar setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS)
para que, cuando cambie el enfoque después del cambio al "modo táctil" o desde este, la vista deseada reciba el enfoque.
- Usa
requestFocus()
y clearFocus()
con cuidado:
- Cuando llames a
requestFocus()
, asegúrate de que sea apropiado que la vista esté enfocada. Si la vista está fuera de la pantalla o cubierta por otra, podrían generarse acciones inesperadas cuando los gestos activen las devoluciones de llamada.
- El método
clearFocus()
inicia una búsqueda de enfoque para encontrar otra vista adecuada. Según la jerarquía de vistas, esta búsqueda puede requerir cálculos no triviales. También puede terminar asignando el enfoque a una vista de forma inesperada.
Los eventos de tecla se envían primero a la vista con enfoque en la jerarquía de vistas. Si la vista enfocada no controla el evento (en otras palabras, muestra false
), el evento no se entrega a la vista superior, incluso si puede recibir el enfoque y tiene un
KeyListener
. En su lugar, el evento se entrega a la actividad actual, por lo que se mantiene la jerarquía de vistas con enfoque.
Por lo tanto, podría ser necesario detectar todos los eventos en el nivel superior y, luego, pasar los códigos relevantes hacia abajo.
Como alternativa, puedes dividir en subclases la actividad y anular el método
dispatchKeyEvent(KeyEvent event)
para interceptar teclas cuando sea necesario o manejarlas cuando no se controlen en capas inferiores.
El contenido y las muestras de código que aparecen en esta página están sujetas a las licencias que se describen en la Licencia de Contenido. Java y OpenJDK son marcas registradas de Oracle o sus afiliados.
Última actualización: 2025-07-26 (UTC)
[[["Fácil de comprender","easyToUnderstand","thumb-up"],["Resolvió mi problema","solvedMyProblem","thumb-up"],["Otro","otherUp","thumb-up"]],[["Falta la información que necesito","missingTheInformationINeed","thumb-down"],["Muy complicado o demasiados pasos","tooComplicatedTooManySteps","thumb-down"],["Desactualizado","outOfDate","thumb-down"],["Problema de traducción","translationIssue","thumb-down"],["Problema con las muestras o los códigos","samplesCodeIssue","thumb-down"],["Otro","otherDown","thumb-down"]],["Última actualización: 2025-07-26 (UTC)"],[],[],null,["# Use wrist gestures on Wear\n\nWrist gestures can enable quick, one-handed interactions with your app\nwhen a touch screen is inconvenient.\n\n\nFor example, a user can scroll\nthrough notifications with one hand while holding a cup of water with the\nother. Other use cases for wrist gestures include the following:\n\n- In a jogging app, navigating through vertical screens that show the steps taken, time elapsed, and current pace\n- In a travel app, scrolling through flight and gate information\n- In a news app, scrolling through articles\n\n\nTo review the [wrist gestures](https://support.google.com/androidwear/answer/6312406) on a watch\ndevice, confirm that gestures are\nturned on by selecting **Settings \\\u003e Advanced features \\\u003e Gestures \\\u003e Wrist Gestures\nOn** . Then complete the\nGestures tutorial on the watch by selecting **Launch Tutorial**.\n\n\n**Note:** Shaking the wrist is the system-wide back or undo gesture\nand is not available for apps to customize.\n\n\nWrist gestures can be used in the following ways, as described in this guide:\n\n- With a [curved layout](#using_wrv), which has predefined gesture actions\n- By using [key events directly](#using_key_events) to define new user actions\n\n\nEach wrist gesture is mapped to an `int` constant from the\n[KeyEvent](/reference/android/view/KeyEvent)\nclass, as shown in the following table:\n\n| Gesture | KeyEvent | Description |\n|-----------------|-------------------------------------------------------------------------------------------|------------------------------------------|\n| Flick wrist out | [`KEYCODE_NAVIGATE_NEXT`](/reference/android/view/KeyEvent#KEYCODE_NAVIGATE_NEXT) | This key code goes to the next item. |\n| Flick wrist in | [`KEYCODE_NAVIGATE_PREVIOUS`](/reference/android/view/KeyEvent#KEYCODE_NAVIGATE_PREVIOUS) | This key code goes to the previous item. |\n\nUse a curved layout to support wrist gestures\n---------------------------------------------\n\n\nThe [WearableRecyclerView](/reference/androidx/wear/widget/WearableRecyclerView) class provides a curved\nlayout for lists and automatically supports\nwrist gestures. The class has predefined actions for occurrences of\nwrist gestures when the view has focus. For information about using\nthe `WearableRecyclerView` class, see [Create lists on Wear OS](/training/wearables/ui/lists). Also, see the\n[Best practices](#best_practices) section of this guide.\n\n\n**Note:** The `WearableRecyclerView` class replaces a similar,\n[deprecated](/training/wearables/ui/wear-ui-library#deprecations) class in the Wearable Support Library.\n\n\nEven if you use a `WearableRecyclerView`, you might want to use\nconstants from the [KeyEvent](/reference/android/view/KeyEvent)\nclass. The predefined actions can be overridden by subclassing the\n`WearableRecyclerView` and re-implementing the\n`onKeyDown()` callback. The behavior can be disabled entirely\nby using [`setEnableGestureNavigation(false)`](/reference/android/support/wearable/view/WearableListView#setEnableGestureNavigation(boolean)).\nFor more information, see\n[Handle keyboard actions](/training/keyboard-input/commands).\n\nUse key events directly\n-----------------------\n\n\nYou can use key events outside of a [WearableRecyclerView](/reference/androidx/wear/widget/WearableRecyclerView) to trigger new actions in response to gesture\nevents. Importantly, these gesture events are recognized when a device is in\nactive mode, and they are delivered in the same way as all key events.\n\n\nA class that relates to user interaction, such as a `View` or an\n`Activity`, and that implements\n[KeyEvent.Callback](/reference/android/view/KeyEvent.Callback) can listen to key events that relate to\nwrist gestures just as it can listed to any other key event. The Android framework\ncalls the `View` or `Activity` that has\nfocus with the key events. For gestures, the `onKeyDown()`\nmethod callback is called when gestures occur.\n\n\nAs an example, an app can override predefined actions in a `View`\nor `Activity` that implements `KeyEvent.Callback` as follows: \n\n### Kotlin\n\n```kotlin\nclass GesturesActivity : Activity() {\n\n /* KeyEvent.Callback */\n override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {\n return when (keyCode) {\n KeyEvent.KEYCODE_NAVIGATE_NEXT -\u003e\n // Do something that advances a user View to the next item in an ordered list.\n moveToNextItem()\n KeyEvent.KEYCODE_NAVIGATE_PREVIOUS -\u003e\n // Do something that advances a user View to the previous item in an ordered list.\n moveToPreviousItem()\n else -\u003e {\n // If you did not handle it, let it be handled by the next possible element as determined\n // by the Activity.\n super.onKeyDown(keyCode, event)\n }\n }\n }\n\n /** Shows the next item in the custom list. */\n private fun moveToNextItem(): Boolean {\n ...\n // Return true if handled successfully, otherwise return false.\n return false\n }\n\n /** Shows the previous item in the custom list. */\n private fun moveToPreviousItem(): Boolean {\n ...\n // Return true if handled successfully, otherwise return false.\n return false\n }\n}\n```\n\n### Java\n\n```java\npublic final class GesturesActivity extends Activity {\n\n @Override /* KeyEvent.Callback */\n public boolean onKeyDown(int keyCode, KeyEvent event) {\n switch (keyCode) {\n case KeyEvent.KEYCODE_NAVIGATE_NEXT:\n // Do something that advances a user View to the next item in an ordered list.\n return moveToNextItem();\n case KeyEvent.KEYCODE_NAVIGATE_PREVIOUS:\n // Do something that advances a user View to the previous item in an ordered list.\n return moveToPreviousItem();\n }\n // If you did not handle it, let it be handled by the next possible element as determined by the Activity.\n return super.onKeyDown(keyCode, event);\n }\n\n /** Shows the next item in the custom list. */\n private boolean moveToNextItem() {\n boolean handled = false;\n ...\n // Return true if handled successfully, otherwise return false.\n return handled;\n }\n\n /** Shows the previous item in the custom list. */\n private boolean moveToPreviousItem() {\n boolean handled = false;\n ...\n // Return true if handled successfully, otherwise return false.\n return handled;\n }\n}\n```\n\nBest practices\n--------------\n\n- Review the [KeyEvent](/reference/android/view/KeyEvent) and [KeyEvent.Callback](/reference/android/view/KeyEvent.Callback) pages for the delivery of key events to your `View` and `Activity`.\n- Keep a consistent directional affordance: use \"flick wrist out\" for next and \"flick wrist in\" for previous.\n- Have a touch parallel for a gesture.\n- Provide visual feedback.\n- Don't use a keycode to implement functionality that would be counterintuitive to the rest of the system. For example, don't use `KEYCODE_NAVIGATE_NEXT` to cancel an action or to navigate the left-right axis with flicks.\n- Don't intercept the key events on elements that are not part of the user interface, such as views that are offscreen or partially covered. This is the same as for any key event.\n- Don't reinterpret repeated flick gestures into your own novel gesture. This might conflict with the system's \"shaking the wrist\" gesture.\n- For a view to receive gesture key events, it must have [focus](/reference/android/view/View#attr_android:focusable); see [`\n View.setFocusable()`](/reference/android/view/View#setFocusable(boolean)).\n\n Because gestures are treated as key events,\n they trigger a transition out of \"touch mode\" that might do unexpected\n things. Since users may alternate between using touch and\n gestures, the [`\n View::setFocusableInTouchmode()`](/reference/android/view/View#setFocusableInTouchMode(boolean)) method could be necessary. In some\n cases, it also could be necessary to use\n `setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS)` so\n that when focus changes after a change to or from touch mode, your\n intended view gets the focus.\n- Use [requestFocus()](/reference/android/view/View#requestFocus()) and [clearFocus()](/reference/android/view/View#clearFocus()) carefully:\n - When calling `requestFocus()`, make sure it's appropriate for the view to have focus. If the view is offscreen or is covered by another view, surprises can occur when gestures trigger callbacks.\n - The `clearFocus()` method initiates a focus search to find another suitable view. Depending on the view hierarchy, this search might require nontrivial computation. It can also end up assigning focus to a view you don't expect to receive focus.\n- Key events are delivered first to the view with focus in the view\n hierarchy. If the focused view does not handle the event---in other words, it returns\n `false`---the event is not delivered to the parent view, even\n if it can receive focus and has a [`\n KeyListener`](/reference/android/text/method/KeyListener). Rather, the event is delivered to the current activity\n holding the view hierarchy with focus.\n\n Therefore, it might be necessary to\n catch all events at the higher level, then pass relevant codes down.\n Alternatively, you might subclass the activity and override the\n [dispatchKeyEvent(KeyEvent event)](/reference/android/app/Activity#dispatchKeyEvent(android.view.KeyEvent)) method to intercept keys\n when necessary or handle them when they are not handled at\n lower layers."]]