Utiliser les mouvements du poignet sur Wear

Les mouvements du poignet vous permettent d'interagir d'une seule main avec votre application lorsqu'il n'est pas facile d'utiliser l'écran tactile.

Par exemple, un utilisateur peut faire défiler les notifications avec une main tout en tenant un verre d'eau dans l'autre. Voici d'autres cas d'utilisation des mouvements du poignet :

  • Dans une application de jogging, vous pouvez parcourir les écrans verticaux qui indiquent le nombre de pas effectués, le temps écoulé et l'allure actuelle.
  • Dans une application de voyage, vous pouvez faire défiler les informations sur les vols et les portes d'embarquement.
  • Dans une application d'actualités, vous pouvez faire défiler les articles.

Pour vérifier les fonctionnalités associées aux mouvements du poignet sur votre montre, confirmez que les gestes sont activés en accédant à Paramètres > Fonctionnalités avancées > Gestes > Mouvements du poignet. Effectuez ensuite le tutoriel sur les gestes en sélectionnant Lancer le tutoriel.

Remarque : Secouer le poignet est le geste d'annulation ou de retour pour tout le système. Ce geste ne peut pas être personnalisé pour une application.

Les mouvements du poignet peuvent être utilisés des manières suivantes, comme décrit dans ce guide :

Chaque mouvement du poignet est mappé à une constante int de la classe KeyEvent, comme indiqué dans le tableau suivant :

Geste Événement de touche Description
Tournez le poignet vers l'extérieur. KEYCODE_NAVIGATE_NEXT Ce code de clavier permet de passer à l'élément suivant.
Tournez le poignet vers l'intérieur. KEYCODE_NAVIGATE_PREVIOUS Ce code de clavier permet de passer à l'élément précédent.

Utiliser une mise en page incurvée pour permettre les mouvements du poignet

La classe WearableRecyclerView offre une mise en page incurvée pour les listes et accepte automatiquement les mouvements du poignet. Elle comporte des actions prédéfinies pour les mouvements du poignet lorsque la vue est ciblée. Pour en savoir plus sur l'utilisation de la classe WearableRecyclerView, consultez Créer des listes sur Wear OS. Consultez également la section Bonnes pratiques de ce guide.

Remarque : La classe WearableRecyclerView remplace une classe similaire obsolète de la bibliothèque Wearable Support.

Même si vous utilisez une propriété WearableRecyclerView, vous pouvez vous servir des constantes de la classe KeyEvent. Les actions prédéfinies peuvent être remplacées en sous-classant WearableRecyclerView et en implémentant de nouveau le rappel onKeyDown(). Vous pouvez désactiver entièrement ce comportement à l'aide de setEnableGestureNavigation(false). Pour en savoir plus, consultez Gérer les actions du clavier.

Utiliser des événements de touche directement

Pour déclencher de nouvelles actions en réponse à des événements gestuels, vous pouvez utiliser des événements de touche en dehors d'un WearableRecyclerView. Il est important de noter que ces événements gestuels sont reconnus lorsqu'un appareil est en mode Actif. Ils sont diffusés de la même manière que tous les événements de touche.

Une classe liée à l'interaction de l'utilisateur, comme View ou Activity, et qui implémente KeyEvent.Callback peut écouter les événements de touche liés aux mouvements du poignet comme tout autre événement de touche. Le framework Android appelle le View ou l'Activity ciblés avec les événements de touche. Pour les gestes, le rappel de la méthode onKeyDown() est appelé lorsque des gestes se produisent.

Par exemple, une application peut ignorer des actions prédéfinies dans un View ou un Activity implémentant KeyEvent.Callback comme suit :

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;
 }
}

Bonnes pratiques

  • Examinez les pages KeyEvent et KeyEvent.Callback concernant la diffusion des événements de touche pour vos View et Activity.
  • Assurez-vous de proposer une affordance directionnelle cohérente : si la rotation de poignet vers l'extérieur est utilisée pour passer à l'élément suivant, la rotation vers l'intérieur peut faire passer à l'élément précédent.
  • Effectuez une pression en parallèle pour un geste.
  • Fournissez des commentaires visuels.
  • N'utilisez pas de code de clavier pour implémenter une fonctionnalité qui serait contre-intuitive par rapport au reste du système. Par exemple, n'utilisez pas KEYCODE_NAVIGATE_NEXT pour annuler une action ou parcourir l'axe de gauche à droite à l'aide d'une rotation du poignet.
  • N'interceptez pas les événements de touche au niveau d'éléments qui ne font pas partie de l'interface utilisateur, tels que les vues qui sont hors de l'écran ou partiellement couvertes. C'est la même chose que pour un événement de touche.
  • Ne réinterprétez pas les mouvements du poignet répétés dans un geste inédit qui vous est propre. Il risque de créer en conflit avec le geste "Secouer le poignet" utilisé au niveau du système.
  • Pour qu'une vue reçoive des événements gestuels de touche, elle doit être ciblée. Consultez la section consacrée à View.setFocusable().

    Étant donné que les gestes sont traités comme des événements de touche, ils déclenchent une transition qui quitte le "mode tactile" et qui peut donc entraîner des actions inattendues. Comme les utilisateurs peuvent alterner entre l'écran tactile et les gestes, la méthode View::setFocusableInTouchmode() peut être requise. Dans certains cas, il peut également être nécessaire d'utiliser setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS) pour que la vue souhaitée soit sélectionnée lorsque le ciblage passe d'un mode à l'autre (mode tactile ou gestes).

  • Attention à l'utilisation de requestFocus() et de clearFocus() :
    • Lorsque vous appelez la méthode requestFocus(), assurez-vous qu'elle est appropriée pour cibler la vue. Si la vue se trouve hors de l'écran ou est recouverte par une autre vue, les gestes déclenchant des rappels peuvent avoir des conséquences inattendues.
    • La méthode clearFocus() lance une recherche de ciblage pour trouver une autre vue appropriée. En fonction de la hiérarchie des vues, cette recherche peut nécessiter des calculs complexes. Elle peut également finir par attribuer le ciblage à une vue que vous ne vous attendiez pas à voir.
  • Les événements de touche sont d'abord envoyés à la vue ciblée dans la hiérarchie des vues. Si cette vue ciblée ne gère pas l'événement (par exemple, si elle renvoie false), celui-ci n'est pas envoyé à la vue parent, même s'il peut être ciblé et qu'il dispose d'un KeyListener. À la place, l'événement est envoyé à l'activité actuelle, qui contient la hiérarchie des vues.

    Par conséquent, il peut être nécessaire d'identifier tous les événements au niveau supérieur, puis de transmettre les codes souhaités à tous les enfants. Vous pouvez également sous-classer l'activité et remplacer la méthode dispatchKeyEvent(KeyEvent event) pour vous assurer que les touches sont interceptées si nécessaire ou pour les prendre en charge lorsqu'elles ne sont pas gérées dans des couches inférieures.