Sur les appareils à grand écran, les utilisateurs interagissent souvent avec les applications à l'aide d'un clavier, d'une souris, d'un pavé tactile, d'un stylet ou d'une manette de jeu. Pour autoriser votre application à accepter les entrées provenant d'appareils externes, procédez comme suit:
- Testez la compatibilité de base avec le clavier, par exemple Ctrl+Z pour annuler, Ctrl+C pour copier et Ctrl+S pour enregistrer. Consultez la section Gérer les actions du clavier pour obtenir la liste des raccourcis clavier par défaut.
- Testez la prise en charge avancée du clavier, par exemple la navigation au clavier avec la touche Tabulation et les touches fléchées, la confirmation d'entrées de texte avec la touche Entrée, et l'utilisation de la barre d'espace pour lire et mettre en pause le contenu dans les applications multimédias.
- Testez les interactions de base de la souris, y compris le clic droit pour afficher le menu contextuel, les modifications d'icône au passage de la souris, et l'utilisation de la molette ou du pavé tactile pour faire défiler les événements sur des composants personnalisés.
- Testez les périphériques d'entrée spécifiques aux applications, comme le stylet, les manettes de jeu et les télécommandes MIDI pour les applications musicales.
- Envisagez de proposer des modes d'entrée avancés qui permettraient à l'application de se démarquer dans les environnements de bureau (par exemple, le pavé tactile comme fondu enchaîné pour les applications de DJ, la capture de souris pour les jeux et un large éventail de raccourcis clavier).
Clavier
La manière dont votre application réagit à la saisie au clavier contribue à l'expérience utilisateur sur grand écran. Il existe trois types de saisie au clavier : navigation, touches et raccourcis.
Navigation
La navigation au clavier est rarement implémentée dans les applications centrées sur l'écran tactile, mais les utilisateurs s'y attendent lorsqu'ils utilisent une application et qu'ils ont un clavier à leur disposition. La navigation au clavier peut être essentielle sur les téléphones, les tablettes, les appareils pliables et les ordinateurs pour les utilisateurs ayant des besoins d'accessibilité.
Pour de nombreuses applications, la navigation avec les touches fléchées et la touche Tabulation est gérée automatiquement par le framework Android. Par exemple, certains composables peuvent être sélectionnés par défaut, comme un Button
ou un composable avec le modificateur clickable
. La navigation au clavier devrait généralement fonctionner sans code supplémentaire. Pour activer la navigation au clavier pour les composables personnalisés qui ne sont pas sélectionnables par défaut, ajoutez le modificateur focusable
:
var color by remember { mutableStateOf(Green) } Box( Modifier .background(color) .onFocusChanged { color = if (it.isFocused) Blue else Green } .focusable() ) { Text("Focusable 1") }
Pour en savoir plus, consultez la section Rendre un composable pouvant être mis au point.
Lorsque la sélection est activée, le framework Android crée un mappage de navigation pour tous les composants sélectionnables en fonction de leur position. Cela fonctionne généralement normalement. Aucun développement supplémentaire n'est donc nécessaire.
Toutefois, Compose ne détermine pas toujours le bon élément suivant pour la navigation par onglets pour les composables complexes tels que les onglets et les listes, par exemple, lorsque l'un des composables est un élément horizontal à faire défiler qui n'est pas entièrement visible.
Pour contrôler le comportement de sélection, ajoutez le modificateur focusGroup
au composable parent d'une collection de composables. Le focus se déplace vers le groupe, puis à travers le groupe avant de passer au prochain composant sélectionnable, par exemple:
Row {
Column(Modifier.focusGroup()) {
Button({}) { Text("Row1 Col1") }
Button({}) { Text("Row2 Col1") }
Button({}) { Text("Row3 Col1") }
}
Column(Modifier.focusGroup()) {
Button({}) { Text("Row1 Col2") }
Button({}) { Text("Row2 Col2") }
Button({}) { Text("Row3 Col2") }
}
}
Pour en savoir plus, consultez Fournir une navigation cohérente avec des groupes de discussion.
Testez l'accès à chaque élément d'interface utilisateur de votre application à l'aide du clavier uniquement. Les éléments fréquemment utilisés doivent être accessibles sans utiliser la souris ni la saisie tactile.
N'oubliez pas que le clavier peut être essentiel aux utilisateurs ayant des besoins d'accessibilité spécifiques.
Touches de clavier
Pour la saisie de texte qui serait gérée par un clavier virtuel à l'écran (IME), comme pour, TextField
,Pour les touches que le framework ne peut pas anticiper, les applications doivent gérer ce comportement elles-mêmes. Cela est particulièrement vrai pour les applications avec des vues personnalisées.
Il peut s'agir d'applications de chat qui utilisent la touche Entrée pour envoyer un message, d'applications multimédias qui lancent et arrêtent la lecture avec la barre d'espace, ou de jeux qui contrôlent le mouvement avec les touches w, a, s et d.
Vous pouvez gérer des frappes individuelles avec le modificateur onKeyEvent
, qui accepte un lambda appelé lorsque le composant modifié reçoit un événement de touche.
La propriété KeyEvent#type
vous permet de déterminer si l'événement est une pression sur une touche (KeyDown
) ou un relâchement de touche (KeyUp
):
Box(
modifier = Modifier.focusable().onKeyEvent {
if(
it.type == KeyEventType.KeyUp &&
it.key == Key.S
) {
doSomething()
true
} else {
false
}
}
) {
Text("Press S key")
}
Vous pouvez également remplacer le rappel onKeyUp()
et ajouter le comportement attendu pour chaque code clavier reçu:
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean { return when (keyCode) { KeyEvent.KEYCODE_ENTER -> { sendChatMessage() true } KeyEvent.KEYCODE_SPACE -> { playOrPauseMedia() true } else -> super.onKeyUp(keyCode, event) } }
Un événement onKeyUp
se produit lorsqu'une touche est relâchée. L'utilisation du rappel évite aux applications de devoir traiter plusieurs événements onKeyDown
si une touche est maintenue enfoncée ou si elle est libérée lentement. Les jeux et les applications qui doivent détecter le moment où une touche est enfoncée ou si l'utilisateur maintient une touche enfoncée peuvent écouter l'événement onKeyDown
et gérer eux-mêmes les événements onKeyDown
répétés.
Pour en savoir plus, consultez Gérer les actions du clavier.
Raccourcis
Les raccourcis clavier courants qui incluent les touches Ctrl, Alt, Maj et Meta sont attendus lorsque vous utilisez un clavier physique. Si une application n'implémente pas de raccourcis, l'expérience peut être frustrante pour les utilisateurs. Les utilisateurs avancés apprécient également les raccourcis pour les tâches fréquentes spécifiques aux applications. Les raccourcis contribuent à la facilité d'utilisation d'une application et la différencient de celles qui n'en ont pas.
Les raccourcis les plus courants sont Ctrl+S (Enregistrer), Ctrl+Z (Annuler) et Ctrl+Maj+Z (Répéter). Pour obtenir la liste des raccourcis par défaut, consultez Gérer les actions du clavier.
Un objet KeyEvent
possède les attributs suivants, qui indiquent si des touches de modification sont enfoncées:
Exemple :
Box(
Modifier.onKeyEvent {
if (it.isAltPressed && it.key == Key.A) {
println("Alt + A is pressed")
true
} else {
false
}
}
.focusable()
)
Pour en savoir plus, consultez les ressources suivantes :
Stylet
De nombreux appareils à grand écran sont livrés avec un stylet. Les applications Android gèrent les stylets comme la saisie tactile. Certains appareils peuvent également disposer d'une table de dessin USB ou Bluetooth, comme Wacom Intuos. Les applications Android peuvent recevoir une entrée Bluetooth, mais pas une entrée USB.
Pour accéder aux objets MotionEvent
du stylet, ajoutez le modificateur pointerInteropFilter
à une surface de dessin. Implémentez une classe ViewModel
avec une méthode qui traite les événements de mouvement. Transmettez la méthode en tant que lambda onTouchEvent
du modificateur pointerInteropFilter
:
@Composable
@OptIn(ExperimentalComposeUiApi::class)
fun DrawArea(modifier: Modifier = Modifier) {
Canvas(modifier = modifier
.clipToBounds()
.pointerInteropFilter {
viewModel.processMotionEvent(it)
}
) {
// Drawing code here.
}
}
L'objet MotionEvent
contient des informations sur l'événement:
MotionEvent#getToolType()
renvoieTOOL_TYPE_FINGER
,TOOL_TYPE_STYLUS
ouTOOL_TYPE_ERASER
en fonction de l'outil qui est entré en contact avec l'écran.MotionEvent#getPressure()
indique la pression physique appliquée au stylet (le cas échéant).MotionEvent#getAxisValue()
avecMotionEvent.AXIS_TILT
etMotionEvent.AXIS_ORIENTATION
fournissent l'inclinaison et l'orientation physiques du stylet (le cas échéant).
Points historiques
Android regroupe les événements d'entrée et les distribue une fois par frame. Un stylet peut signaler des événements avec une fréquence beaucoup plus élevée que l'écran. Lorsque vous créez des applications de dessin, recherchez les événements récents à l'aide des API getHistorical
:
MotionEvent#getHistoricalX()
MotionEvent#getHistoricalY()
MotionEvent#getHistoricalPressure()
MotionEvent#getHistoricalAxisValue()
Refus de la paume de la main
Lorsque les utilisateurs dessinent, écrivent ou interagissent avec votre application à l'aide d'un stylet, ils touchent parfois l'écran avec la paume de leur main. L'événement tactile (défini sur ACTION_DOWN
ou ACTION_POINTER_DOWN
) peut être signalé à votre application avant que le système ne le reconnaisse et n'ignore la pression involontaire via la paume de la main.
Android annule les événements tactiles de la paume de la main en envoyant un MotionEvent
. Si votre application reçoit ACTION_CANCEL
, annulez le geste. Si votre application reçoit une erreur ACTION_POINTER_UP
, vérifiez si FLAG_CANCELED
est défini. Si c'est le cas, annulez le geste.
Ne recherchez pas uniquement FLAG_CANCELED
. Sur Android 13 (niveau d'API 33) ou version ultérieure, le système définit FLAG_CANCELED
pour les événements ACTION_CANCEL
, mais il ne définit pas l'indicateur sur les versions Android antérieures.
Android 12
Sur Android 12 (niveau d'API 32) et versions antérieures, la détection du refus de la paume de la main n'est possible que pour les événements tactiles à un seul pointeur. Si une pression via la paume de la main est le seul pointeur, le système annule l'événement en définissant ACTION_CANCEL
sur l'objet d'événement de mouvement. Si les autres pointeurs impliquent une pression, le système définit ACTION_POINTER_UP
, ce qui est insuffisant pour détecter le refus de la paume de la main.
Android 13
Sur Android 13 (niveau d'API 33) ou version ultérieure, si une pression via la paume de la main est le seul pointeur, le système annule l'événement en définissant ACTION_CANCEL
et FLAG_CANCELED
sur l'objet d'événement de mouvement. Si les autres pointeurs impliquent une pression, le système définit ACTION_POINTER_UP
et FLAG_CANCELED
.
Chaque fois que votre application reçoit un événement de mouvement avec ACTION_POINTER_UP
, recherchez FLAG_CANCELED
pour déterminer si l'événement indique un refus de la paume de la main (ou une autre annulation d'événement).
Applications de prise de notes
ChromeOS utilise un intent spécial qui présente aux utilisateurs les applications de prise de notes enregistrées en tant que telles. Pour enregistrer une application en tant qu'application de prise de notes, ajoutez le code suivant à votre fichier manifeste d'application:
<intent-filter>
<action android:name="org.chromium.arc.intent.action.CREATE_NOTE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
Lorsqu'une application est enregistrée auprès du système, l'utilisateur peut la sélectionner comme application de prise de notes par défaut. Lorsqu'une nouvelle note est demandée, l'application doit créer une note vide prête à être saisie par le stylet. Lorsque l'utilisateur souhaite annoter une image (par exemple, une capture d'écran ou une image téléchargée), l'application se lance avec ClipData
et contient un ou plusieurs éléments avec des URI content://
. L'application doit créer une note qui utilise la première image jointe comme image d'arrière-plan et passer dans un mode permettant à l'utilisateur de dessiner à l'écran avec un stylet.
Tester les intents de prise de notes sans stylet
[TBD remove section.]
Pour vérifier si une application répond correctement aux intents de prise de notes sans stylet actif, utilisez la méthode suivante afin d'afficher les options de prise de notes sur ChromeOS:
- Activez le mode développeur et rendez l'appareil accessible en écriture.
- Appuyez sur Ctrl+Alt+F2 pour ouvrir un terminal.
- Exécutez la commande
sudo vi /etc/chrome_dev.conf
. - Appuyez sur
i
pour effectuer des modifications, puis ajoutez--ash-enable-palette
à une nouvelle ligne à la fin du fichier - Pour enregistrer, appuyez sur Échap, puis saisissez :, w, q et appuyez sur Entrée.
- Appuyez sur Ctrl+Alt+F1 pour revenir à l'interface utilisateur ChromeOS standard.
- Déconnectez-vous, puis reconnectez-vous.
Un menu de stylet devrait maintenant s'afficher sur l'étagère:
- Appuyez sur le bouton du stylet situé sur l'étagère, puis sélectionnez Nouvelle note. Une note de dessin vide devrait s'afficher.
- Prenez une capture d'écran. À partir de l'étagère, sélectionnez Bouton du stylet > Capturer l'écran ou téléchargez une image. L'option Annoter l'image devrait s'afficher dans la notification. Celle-ci devrait lancer l'application avec l'image prête à être annotée.
Compatibilité avec la souris et le pavé tactile
La plupart des applications ne doivent généralement gérer que trois événements axés sur les grands écrans : effectuer un clic droit, pointer le curseur et glisser-déposer.
Effectuer un clic droit
Toutes les actions qui entraînent l'affichage d'un menu contextuel par une application, comme l'appui prolongé sur un élément de la liste, doivent également réagir aux événements de clic droit.
Pour gérer les événements de clic droit, les applications doivent enregistrer un élément View.OnContextClickListener
:
Box(modifier = Modifier.fillMaxSize()) {
AndroidView(
modifier = Modifier.fillMaxSize(),
factory = { context ->
val rootView = FrameLayout(context)
val onContextClickListener =
View.OnContextClickListener { view ->
showContextMenu()
true
}
rootView.setOnContextClickListener(onContextClickListener)
rootView
},
)
}
Pour découvrir comment créer des menus contextuels, consultez Créer un menu contextuel.
Survol
Vous pouvez rendre vos mises en page d'application plus fluides et plus faciles à utiliser en gérant les événements de pointage. C'est particulièrement vrai pour les composantspersonnalisés:
Voici les deux exemples les plus courants:
- Modifier l'icône du pointeur de la souris pour indiquer aux utilisateurs si un élément a un comportement interactif, par exemple s'il est cliquable ou modifiable
- Ajouter un retour visuel aux éléments d'une longue liste ou grille lorsque le pointeur passe dessus
Glisser-déposer
Dans un environnement multifenêtre, les utilisateurs s'attendent à pouvoir glisser-déposer des éléments entre les applications. Cela est le cas pour les ordinateurs, les tablettes, les téléphones et les pliables en mode écran partagé.
Déterminez si les utilisateurs sont susceptibles de faire glisser des éléments dans votre application. Par exemple, les éditeurs de photos doivent s'attendre à recevoir des photos, les lecteurs audio à recevoir des fichiers audio et les programmes de dessin à recevoir des photos.
Pour permettre de glisser-déposer des éléments, consultez les pages Glisser-déposer ainsi que l'article de blog Android sur ChromeOS : implémenter le glisser-déposer.
Remarques concernant ChromeOS
- N'oubliez pas de demander l'autorisation avec
requestDragAndDropPermissions()
pour accéder aux éléments que l'utilisateur fait glisser depuis l'extérieur de l'application. Un élément doit être associé à l'indicateur
View.DRAG_FLAG_GLOBAL
pour pouvoir être glissé vers d'autres applications.
Compatibilité avancée avec les pointeurs
Les applications qui gèrent les commandes avancées de la souris et du pavé tactile doivent implémenter un modificateur
pointerInput
pour obtenir un PointerEvent
:
@Composable private fun LogPointerEvents(filter: PointerEventType? = null) { var log by remember { mutableStateOf("") } Column { Text(log) Box( Modifier .size(100.dp) .background(Color.Red) .pointerInput(filter) { awaitPointerEventScope { while (true) { val event = awaitPointerEvent() // handle pointer event if (filter == null || event.type == filter) { log = "${event.type}, ${event.changes.first().position}" } } } } ) } }
Examinez l'objet PointerEvent
pour déterminer les éléments suivants:
PointerType
: souris, stylet, écran tactile, etc. à partir dePointerEvent#changes
PointerEventType
: actions du pointeur, telles que l'appui, le déplacement, le défilement et la libération
Manettes de jeu
Certains appareils Android à grand écran acceptent jusqu'à quatre manettes de jeu. Utilisez les API de manette de jeu Android standards pour gérer les manettes de jeu (consultez Prendre en charge les manettes de jeu).
Les boutons de la manette de jeu sont mis en correspondance avec des valeurs communes suivant un mappage commun. Cependant, tous les fabricants de manettes de jeu ne suivent pas les mêmes conventions de mappage. Vous offrirez une bien meilleure expérience si vous autorisez les utilisateurs à sélectionner différents mappages de manettes populaires. Pour en savoir plus, consultez la section Traiter les pressions sur les boutons d'une manette de jeu.
Mode de conversion d'entrée
ChromeOS offre un mode de conversion d'entrée par défaut. Pour la plupart des applications Android, ce mode permet aux applications de fonctionner comme prévu dans un environnement de bureau. Par exemple, il permet l'activation automatique du défilement à deux doigts sur le pavé tactile, le défilement de la molette de la souris et le mappage des coordonnées brutes de l'écran avec les coordonnées de la fenêtre. En règle générale, les développeurs d'applications n'ont pas besoin d'implémenter ces comportements eux-mêmes.
Si une application met en œuvre un comportement de saisie personnalisé, par exemple si vous définissez une action personnalisée de pincement avec deux doigts sur le pavé tactile, ou si ces conversions d'entrée ne fournissent pas les événements d'entrée attendus par l'application, vous pouvez désactiver la conversion d'entrée en ajoutant la balise suivante au fichier manifeste Android:
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />