├── LICENSE.md
├── README.md
├── android.md
└── ios.md
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # Licence
2 | Ces documents sont des documents de l'État français placés sous licence ouverte 1.0 ou ultérieure. Vous trouverez des précisions sur cette licence sur le [blog de la mission etalab](http://www.etalab.gouv.fr/licence-ouverte-open-licence).
3 |
4 | Vous êtes libres de :
5 | * Reproduire, copier, publier et transmettre ces informations ;
6 | * Diffuser et redistribuer ces informations ;
7 | * Adapter, modifier, extraire et transformer ces information, notamment pour créer des informations dérivées ;
8 | * Exploiter ces informations à titre commercial, par exemple en la combinant avec d'autres informations, ou enl'incluant dans votre propre produit ou application.
9 |
10 | Ces libertés s'appliquent sous réserve de mentionner la paternité de l'information d'origine : sa source et la date de sa dernière mise à jour. Le réutilisateur peut notamment s'acquitter de cette condition en indiquant un ou des liens hypertextes (URL) renvoyant vers le présent dépôt et assurant une mention effective de sa paternité.
11 |
12 | Cette mention de paternité ne doit ni conférer un caractère officiel à la réutilisation de ces informations, ni suggérer une quelconque reconnaissance ou caution par le producteur de l'information, ou par toute autre entité publique, du réutilisateur ou de sa réutilisation.
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Guide de développement d'applications mobiles accessibles avec les API Android et iOS
2 |
3 | Ce guide s'adresse aux développeurs d'applications mobiles qui souhaitent
4 | connaître les techniques à utiliser pour créer des applications accessibles
5 | avec les API fournies par les systèmes Android et iOS. Pour chaque
6 | environnement, l'accessibilité des widgets
7 | le plus courants a été testés avec les lecteurs d'écran.
8 |
9 | Deux documents distincts sont proposés pour :
10 |
11 | * [Android](./android.md)
12 | * [iOS](./ios.md)
13 |
14 | Le guide est [disponible également en anglais](https://github.com/DISIC/guide-mobile_app_dev_natif/tree/english).
15 |
16 | ## Guides connexes
17 |
18 | Les guides suivants peuvent être consultés en complément :
19 |
20 | * [Guide d'audit d'applications mobiles](https://github.com/DISIC/guide-mobile_app_audit)
21 | * [Guide de conception d'applications mobiles accessibles](https://github.com/DISIC/guide-mobile_app_conception)
22 | * [Guide de développement d'applications mobiles accessibles avec Ionic et OnsenUI](https://github.com/DISIC/guide-mobile_app_dev_hybride)
23 |
24 | ## Licence
25 | Ce document est la propriété du Secrétariat général à la modernisation de l'action publique français (SGMAP). Il est placé sous la [licence ouverte 1.0 ou ultérieure](http://www.etalab.gouv.fr/licence-ouverte-open-licence), équivalente à une licence Creative Commons BY. Pour indiquer la paternité, ajouter un lien vers la version originale du document disponible sur le [compte Github de la DInSIC](https://github.com/DISIC).
26 |
27 |
--------------------------------------------------------------------------------
/android.md:
--------------------------------------------------------------------------------
1 | # Guide de développement d'applications accessibles mobiles avec l'API Android
2 |
3 | ## Sommaire
4 |
5 | * [Sommaire](#sommaire)
6 | * [À qui s'adresse ce guide ?](#%C3%A0-qui-sadresse-ce-guide )
7 | * [Généralités sur Android et l'accessibilité](#g%C3%A9n%C3%A9ralit%C3%A9s-sur-android-et-laccessibilit%C3%A9)
8 | * [Utliser les éléments de base fournis par l'API Android](#utliser-les-%C3%A9l%C3%A9ments-de-base-fournis-par-lapi-android)
9 | * [Widgets compatibles](#widgets-compatibles)
10 | * [Widgets incompatibles](#widgets-incompatibles)
11 | * [Tester l'accessibilité](#tester-laccessibilit%C3%A9)
12 | * [Décrire les éléments d'interface](#d%C3%A9crire-les-%C3%A9l%C3%A9ments-dinterface)
13 | * [Exemples de création statique](#exemples-de-cr%C3%A9ation-statique)
14 | * [ImageView et ImageButton](#imageview-et-imagebutton)
15 | * [CheckBox](#checkbox)
16 | * [EditText](#edittext)
17 | * [Mise à jour dynamique de la description des contenus](#mise-%C3%A0-jour-dynamique-de-la-description-des-contenus)
18 | * [Permettre la modification de la taille des caractères](#permettre-la-modification-de-la-taille-des-caract%C3%A8res)
19 | * [Gérer le focus](#g%C3%A9rer-le-focus)
20 | * [Activer la prise de focus](#activer-la-prise-de-focus)
21 | * [Contrôler l'ordre de lecture](#contr%C3%B4ler-lordre-de-lecture)
22 | * [Afficher la prise de focus](#afficher-la-prise-de-focus)
23 | * [Masquer les éléments décoratifs](#masquer-les-%C3%A9l%C3%A9ments-d%C3%A9coratifs)
24 | * [Forcer la restitution des éléments importants non focusables](#forcer-la-restitution-des-%C3%A9l%C3%A9ments-importants-non-focusables)
25 | * [Regrouper des éléments](#regrouper-des-%C3%A9l%C3%A9ments)
26 | * [Gérer des événements liés à l'accessibilité](#g%C3%A9rer-des-%C3%A9v%C3%A9nements-li%C3%A9s-%C3%A0-laccessibilit%C3%A9)
27 | * [AccessibilityEvent](#accessibilityevent)
28 | * [Cheminement des événements](#cheminement-des-%C3%A9v%C3%A9nements)
29 | * [Récupérer plus d'informations sur le contexte avec AccessibilityNodeInfo](#r%C3%A9cup%C3%A9rer-plus-dinformations-sur-le-contexte-avec-accessibilitynodeinfo)
30 | * [Créer des vues personnalisées accessibles](#cr%C3%A9er-des-vues-personnalis%C3%A9es-accessibles)
31 | * [Gérer la navigation par contrôleurs directionnels](#g%C3%A9rer-la-navigation-par-contr%C3%B4leurs-directionnels)
32 | * [Implémenter les méthodes pour l'accessibilité](#impl%C3%A9menter-les-m%C3%A9thodes-pour-laccessibilit%C3%A9)
33 | * [onInitializeAccessibilityEvent()](#oninitializeaccessibilityevent)
34 | * [onInitializeAccessibilityNodeInfo()](#oninitializeaccessibilitynodeinfo)
35 | * [onPopulateAccessibilityEvent()](#onpopulateaccessibilityevent)
36 | * [Gérer le cas des gestes personnalisés](#g%C3%A9rer-le-cas-des-gestes-personnalis%C3%A9s)
37 | * [Pour aller plus loin](#pour-aller-plus-loin)
38 | * [Guides connexes](#guides-connexes)
39 | * [Ressources externes et références](#ressources-externes-et-r%C3%A9f%C3%A9rences)
40 | * [Licence](#licence)
41 |
42 | ## À qui s'adresse ce guide ?
43 |
44 | Ce guide présente des éléments de l'API d'Android utiles pour développer des applications accessibles aux personnes en situation de handicap. Il s'adresse :
45 |
46 | * Aux développeurs
47 | * Aux concepteurs en charge de la rédaction de spécifications techniques
48 | * Aux chefs de projets
49 |
50 | Pré-requis :
51 |
52 | * Maîtriser les langages Java et XML
53 | * Maîtriser les principes de programmation sous Android
54 | * Connaître les classes de base de l'environnement Android (notamment "activity" et "service")
55 | * Maîtriser la gestion d'événements
56 | * Maîtriser les concepts utilisés pour gérer les interfaces utilisateurs sous Android (vues, layouts, etc.) et les principaux éléments de l'API (TextView, CheckBox, RadioButton, etc.)
57 |
58 |
59 | ## Généralités sur Android et l'accessibilité
60 |
61 | L'API Android met à disposition des développeurs des fonctionnalités permettant de créer des applications accessibles. Ces fonctionnalités sont présentes dans les classes qui permettent de créer les éléments de base d'une interface utilisateur ainsi que dans des classes dédiées à l'accessibilité.
62 |
63 | Les applications Android peuvent être utilisées par des personnes en situation de handicap (visuel, moteur, etc.), grâce à l'activation de services dédiés à l'accessibilité sur l'appareil utilisé pour exécuter l'application et parfois grâce à l'utilisation de périphériques externes (claviers, commutateurs, plages braille, etc.). Les services d'accessibilité peuvent être activés en se rendant dans les paramètres de l'appareil, dans l'onglet "Accessibilité".
64 |
65 | Google développe plusieurs services :
66 |
67 | * Le lecteur d'écran TalkBack, qui vocalise la navigation à l'intérieur des applications. Il propose plusieurs fonctionnalités :
68 | * Exploration tactile : l'utilisateur explore le contenu de l'application en parcourant l'écran avec les doigts. TalkBack pilote un logiciel de synthèse vocale qui prononce les informations relatives aux éléments explorés positionnés sous les doigts de l'utilisateur. Dans ce mode, TalBack redéfinit les gestes "standards" : l'activation d'un élément se fait par exemple par un "double tap".
69 | * Navigation gestuelle simplifiée : TalkBack redéfinit des gestes permettant à l'utilisateur de naviguer facilement entre les différents éléments de l'interface.
70 | * Retour haptique : lorsque des éléments d'interface sont activés (entrée dans une zone de saisie par exemple), TalkBack le signale à l'utilisateur par des vibrations.
71 | * BrailleBack, qui permet aux utilisateur possédant des appareils de lecture braille éphémère de les connecter via USB ou Bluetooth à leur appareil Android pour lire et interagir avec le contenu des applications.
72 |
73 | De même que certains constructeurs proposent des versions modifiées du système Android, il existe des versions modifiées des services d'accessibilité : c'est par exemple le cas des certains téléphones de la marque Samsung qui sont livrés avec le service Galaxy TalkBack, une version du lecteur d'écran basée sur celui développé par Google.
74 |
75 | La simple activation de services d'accessibilité ne suffit pas à rendre une application pleinement accessible : le développeur doit mettre en oeuvre des techniques particulières lors du codage de l'application pour rendre son contenu exploitable par les services d'accessibilité.
76 |
77 | Lorsque l'interface utilisateur d'une application est constituée d'éléments de base fournis par le framework Android, la mise en oeuvre de l'accessibilité est relativement simple. La démarche est la suivante :
78 |
79 | 1. Décrire les éléments d'interface pour que leur contenu soit restitué par les services d'accessibilité
80 | 2. Faire en sorte que tous les éléments qui appellent une interaction puissent être atteints par un contrôleur directionnel (trackball, D-pad, etc.)
81 | 3. Faire en sorte que les messages audio soient accompagnés par des notifications visuelles et/ou haptiques, pour être perçues par les personnes sourdes ou malentendantes
82 |
83 | Afin de développer des interfaces plus complexes et personnalisées qui nécessitent d'étendre la classe View, il sera nécessaire de s'assurer que ces éléments sont compatibles avec les services d'accessibilité en redéfinissant certaines méthodes, notamment pour gérer correctement les événements liés à l'accessibilité.
84 |
85 | ## Utliser les éléments de base fournis par l'API Android
86 |
87 | L'API d'Android fournit des éléments de base (widgets,
88 | views) qui implémentent correctement l'accessibilité dans la plupart
89 | des cas. Il convient en premier lieu de privilégier l'utilisation de ces
90 | éléments et de n'en définir de nouveaux qu'en cas de nécessité.
91 |
92 | Nous listons ci-dessous des éléments compatibles et non compatibles avec les
93 | services d'accessibilité. Ils ont été testés avec les versions d'Android 4.3,
94 | 4.4 et 5.1.
95 |
96 | ### Widgets compatibles
97 |
98 | Les widgets suivants ont été testés et peuvent être utilisés pour créer des interfaces compatibles avec les services d'accessibilité (en veillant à décrire les contenus et à gérer correctement le focus comme indiqué dans les sections précédentes).
99 |
100 | * EditText
101 | * CheckBox
102 | * ToggleButton
103 | * Switch
104 | * RadiGroup et RadioButton
105 | * Chronometer
106 | * TectClock
107 | * AutoCompleteTextView
108 | * Button
109 | * ProgressBar
110 | * RatingBar
111 | * SeekBar
112 | * NumberPicker
113 | * TextSwitcher
114 |
115 |
116 | Layouts :
117 |
118 | * LinearLayout
119 | * TableLayout
120 |
121 | Vues :
122 |
123 | * TextView
124 | * ImageView
125 | * ListView
126 | * SearchView
127 | * WebView
128 |
129 | ### Widgets incompatibles
130 | En revanche, les widgets suivants ne sont pas compatibles avec les services d'accessibilité. Ils devront être adaptés au cas par cas :
131 |
132 | * TabHost : le contenu des onglets n'est pas restitué correctement par les services d'accessibilité
133 | * DatePicker
134 | * TimePicker
135 | * Spinner
136 | * ToolBar
137 |
138 | Vues :
139 |
140 | * CalendarView
141 | * ExpandableListView
142 | * StackView
143 |
144 | ## Tester l'accessibilité
145 |
146 | Dans l'API Android, les fonctionnalités relatives à l'accessibilité sont "stabilisées" depuis la version 4.0 (il n'y pas de changement majeur dans l'API). Cependant, les services d'accessibilité (TalkBack notamment) évoluent rapidement et changent parfois l'interprétation qu'ils font de certains éléments d'interface ou de certains événements liés à l'accessibilité. Par exemple, la version 4.3.1 de TalkBack parue en octobre 2015 est en mesure de restituer les changements de valeurs des "sliders", ce qui n'était pas le cas dans les versions précédents (on devait alors utiliser l'attribut `contentDescription` pour en restituer le contenu). L'interprétation par les services d'accessibilité des widgets courants est relativement stable : les tests réalisés n'ont pas permis de mettre en évidence des régressions. En revanche, l'interprétation de vues personnalisées peut varier, mais ces variations sont extrêmement complexes à documenter. Par ailleurs, certains constructeurs de matériel peuvent ajouter des surcouches au système Android, ce qui a parfois un impact sur l'accessibilité. Il est ainsi nécessaire de tester l'accessibilité d'une application Android afin de vérifier que les recommandations présentées ci-dessous sont bien prises en compte par les services d'accessibilité (voir le [Guide d'audit d'applications mobiles](https://github.com/DISIC/guide-mobile_app_audit)).
147 |
148 | ## Décrire les éléments d'interface
149 | Un grand nombre d'éléments d'une interface utilisateur fournissent des informations sur leur usage ou sur leur signification grâce à des indications visuelles. Par exemple, une application de prise de note utilise un élément `ImageButton` contenant l'image d'un signe "plus" pour indiquer que l'utilisateur peut ajouter une nouvelle note. Un composant `EditText` peut disposer d'une étiquette qui permet de préciser l'information que l'utilisateur doit saisir. Un utilisateur aveugle ne peut pas percevoir ces indications visuelles. Il est donc nécessaire d'employer un moyen pour ajouter une alternative à ces indications. Pour cela il faut utiliser l'attribut `android:contentDescription` dans la description XML d'un élément d'interface ou la méthode `setContentDescription` dans le code Java. Le texte qui se trouve dans cette description ne sera pas affiché sur l'écran mais sera uniquement traité par les services d'accessibilité lorsque l'utilisateur les aura activés. Avec TalkBack, le texte sera prononcé par le synthétiseur vocal ; avec BrailleBack, le texte apparaîtra à proximité de l'élément sur l'afficheur braille.
150 |
151 | ### Exemples de création statique
152 |
153 | #### ImageView et ImageButton
154 | `ImageView` permet d'afficher une image à l'écran. `ImageButton` est une sous-classe d'`ImageView` qui lui ajoute les comportements d'un bouton "standard". Ces classes possèdent un attribut `android:src` qui désigne une ressource graphique correspondant à l'image qui sera affichée et utilisée pour représenter le bouton dans le cas d'`ImageButton`. Cette ressource graphique ne pouvant pas être interprétée par les services d'accessibilité, il convient d'utiliser l'attribut `android:contentDescription` pour fournir une alternative textuelle à cette image.
155 |
156 | Exemple avec `ImageButton` :
157 | ```xml
158 |
164 | ```
165 |
166 | Comportement attendu avec TalkBack : annonce du contenu de l'attribut `android:contentDescription` précédé du mot "bouton" lors de la prise de focus ou du survol de l'image
167 |
168 |
169 | #### CheckBox
170 | `CheckBox` permet d'implémenter une case à cocher.
171 |
172 | ```xml
173 |
178 | ```
179 |
180 | L'attribut `android:text` contient le texte affiché à l'écran. Il peut être pertinent d'ajouter des éléments de contexte dans l'attribut `android:contentDescription` pour fournir à l'utilisateur des précisions sur l'action qui sera réalisée lors de l'activation ou la désactivation de la case. Par exemple, une vue peut présenter plusieurs cases à cocher disposées en regard d'une liste de produits dont l'utilisateur doit indiquer si oui ou non il souhaite recommander un/des élément(s). Si seulement l'attribut "android:text" est renseigné avec le texte "Recommander", l'utilisateur ne disposera pas de suffisamment d'informations pour savoir quelle action réalisera le fait de cocher la case. Ajouter "Recommander des pivoines" dans l'attribut `android:contentDescription` lui permettra de connaître plus précisément l'action réalisée lorsqu'il utilise un service d'accessibilité.
181 |
182 | Comportement attendu avec TalkBack : prononciation de l'état de la case, suivi de "Case à cocher" puis du contenu de la description.
183 |
184 | #### EditText
185 | `EditText` permet de créer une zone de saisie de texte. Pour `EditText`, contrairement à la plupart des autres widgets disponibles dans le framework Android, l'attribut `android:contentDescription` ne peut pas être utilisé pour véhiculer une information décrivant l'élément (le contenu de l'attribut ne sera pas restitué par les services d'accessibilité).
186 |
187 | L'utilisation de `android:hint` permet à l'utilisateur de comprendre la nature de l'information attendue : le contenu de `android:hint` est une aide à la saisie affichée lorsque la zone de saisie est vide, et lorsque la zone est complétée, le lecteur d'écran restitue le texte saisi au lieu de l'attribut.
188 | ```xml
189 |
193 | ```
194 |
195 | Cependant, le contenu de `android:hint` disparaît dès que l'utilisateur saisit un caractère et ne peut plus être restitué, même si la zone est vidée : cela créé des difficultés notamment dans lorsque plusieurs champs de saisie sont proposés dans une même vue. Le meilleur moyen d'assurer l'accessibilité d'une zone de saisie est d''y associer une étiquette visible en utilisant l'attribut `android:labelFor`.
196 |
197 | En XML :
198 | ```xml
199 |
202 |
203 |
204 | ```
205 |
206 | En Java, les fonctions `setLabelFor(View label)` ou `setLabeledBy(View label)` peuvent être utilisées.
207 |
208 | Comportement attendu avec TalkBack :
209 |
210 | * Le contenu de `android:hint` est restitué uniquement lorsqu'aucun texte n'a été saisi ; lorsqu'un texte a été saisi, celui-ci est restitué par TalkBack ; lorsqu'un texte a été saisi puis supprimé, TalkBack indique seulement la présence de la zone de saisie sans restituer le contenu de `android:hint`.
211 | * Le contenu de `android:labelFor` est restitué quel que soit le contexte.
212 |
213 | ### Mise à jour dynamique de la description des contenus
214 | Lorsque le contenu d'un élément évolue au cours du temps, il est nécessaire de veiller à mettre à jour sa description, notamment lorsque l'état de l'élément ne peut être interprété par un autre moyen que cette description. Pour cela, il faut utiliser la méthode `setContentDescription` dans le code Java de l'application. La mise à jour dynamique de la description est par exemple utile dans les cas suivants, lors de la création de widgets personnalisés :
215 |
216 | * Pour sélectionner une couleur dans une palette : les couleurs doivent être identifiées par une description textuelle et la description indiquant la couleur sélectionnée doit être mise à jour afin que l'utilisateur en ait connaissance lorsqu'il reprendra le focus sur le widget
217 | * Pour sélectionner une date : la description peut être utilisée pour rappeler l'intégralité de la date sélectionnée après la mise à jour d'un des éléments (jour, mois, année) par l'utilisateur
218 | * Pour indiquer le changement de fonction d'un bouton image lorsque sa signification est véhiculée par la forme ou la couleur : un bouton "Lecture" devenant "Pause" par exemple
219 |
220 | Une méthode pour mettre à jour la description est d'utiliser des listeners pour surveiller le changement d'état d'un widget afin de prendre les mesures nécessaires au moment approprié.
221 |
222 | L'exemple ci-dessous met en oeuvre une `SeekBar`, un widget qui permet de saisir une valeur prise dans un intervalle déterminé. TalkBack, dans ses version inférieures à 4.3.1, ne surveillait pas le changement d'état de la `SeekBar` et n'était donc pas en mesure d'informer l'utilisateur des changements de valeurs. Ce comportement est identique avec BrailleBack. Le code proposé surveille la modification de la `SeekBar` et met à jour dynamiquement la description fournie aux services d'accessibilité lorsque la valeur change. Ainsi, la valeur sera indiquée à l'utilisateur après chaque changement, ce qui n'aurait pas été le cas par défaut.
223 | NB : ce code est donné à titre d'exemple avec TalkBack 4.3.1, son utilisation provoque une double restitution lors du changement de la valeur de la `SeekBar`. Il doit donc être considéré comme une illustration du principe de mise à jour dynamique de la description, mais son utilisation n'est pas nécessairement pertinente dans tous les contextes.
224 |
225 | Description XML :
226 | ```xml
227 |
231 |
232 |
236 |
237 | ```
238 |
239 | Code Java :
240 | ```java
241 | package com.braillenet.android_accessibility;
242 |
243 | import android.app.Activity;
244 | import android.os.Bundle;
245 | import android.widget.SeekBar;
246 |
247 | public class ProgressBarActivity extends Activity {
248 |
249 | private SeekBar mReadingSpeed;
250 | String name;
251 |
252 | @Override
253 | protected void onCreate(Bundle savedInstanceState) {
254 | super.onCreate(savedInstanceState);
255 | setContentView(R.layout.progressbar);
256 | mReadingSpeed = (SeekBar)findViewById(R.id.reading_speed);
257 | name = "Vitesse de lecture";
258 | mReadingSpeed.setOnSeekBarChangeListener(new SeekBarListener(name));
259 | mReadingSpeed.setContentDescription(name);
260 | }
261 |
262 | private class SeekBarListener implements SeekBar.OnSeekBarChangeListener {
263 | private String mName;
264 | public SeekBarListener(String name) {
265 | mName = name;
266 | }
267 | public void onProgressChanged(SeekBar seekBar, int progress,
268 | boolean fromUser) {
269 | int percent = 100 * seekBar.getProgress() / seekBar.getMax();
270 | seekBar.setContentDescription(mName + " " + percent + "%");
271 | }
272 | public void onStartTrackingTouch(SeekBar seekBar) {
273 | }
274 | public void onStopTrackingTouch(SeekBar seekBar) {
275 | seekBar.setContentDescription(mName);
276 | }
277 | }
278 | }
279 | ```
280 |
281 | Comportement attendu avec TalkBack : lorsque la valeur est modifiée (on peut utiliser les bouton "+" et "-" du volume pour cela), TalkBack annonce le message "Vitesse de lecture x%".
282 |
283 | ## Permettre la modification de la taille des caractères
284 |
285 | Android propose à l'utilisateur de paramétrer la taille des caractères (menu Paramètres, Accessibilité puis Taille des caractères : Petit, Normal ou Grand). Pour qu'une application réponde correctement à ce paramétrage, il est nécessaire d'utiliser l'unité "sp" (scale-independent pixel) lors de la définition des tailles de texte.
286 | Exemple : ``
287 |
288 | Il est possible de connaître le facteur d'ajustement sélectionné par l'utilisateur appliqué à la taille des caractères, ce qui permet d'adapter le comportement de l'application en conséquence (modifier le nombre de colonnes d'un tableau par exemple). Pour cela, il faut accéder à la valeur `Settings.System.FONT_SCALE` de la table `Settings.System.CONTENT_URI`. (1.0f est la valeur correspondant à la taille "normale").
289 |
290 | Exemple :
291 | ```java
292 | ContentResolver r = getContentResolver();
293 | Cursor c = r.query(Settings.System.CONTENT_URI,
294 | new String[] { Settings.System.VALUE },
295 | Settings.System.NAME + "= ?",
296 | new String[] { Settings.System.FONT_SCALE }, null);
297 | float fs = c.getFloat(0);
298 | if(fs ...) {
299 | ..
300 | } else {
301 | ...
302 | }
303 | ```
304 |
305 | ## Gérer le focus
306 |
307 | Il est nécessaire de permettre aux utilisateurs de naviguer entre les différents éléments de l'interface grâce à un contrôleur directionnel. Un tel contrôleur peut être matériel (trackball, D-Pad, flèches d'un clavier, etc.) ou virtuel comme le clavier fourni par une application ou le mode de navigation gestuelle disponible depuis Android 4.1. La navigation grâce aux contrôleurs directionnels est largement utilisée, notamment par les personnes en situation de handicap moteur.
308 |
309 | Pour s'assurer qu'une telle navigation fonctionne, il est nécessaire de vérifier que tous les éléments d'une application soient atteignables sans utiliser les interactions tactiles. Il est par ailleurs nécessaire de vérifier que cliquer sur le bouton central (ou le bouton OK) d'un contrôleur directionnel a le même effet que de toucher un élément sur l'écran possédant le focus.
310 |
311 | ### Activer la prise de focus
312 |
313 | Un élément d'une interface utilisateur est atteignable en utilisant un contrôleur directionnel lorsque l'attribut `android:focusable` vaut "true" : cela permet à l'utilisateur de prendre le focus sur cet élément et d'interagir avec le contenu. Les éléments de base fournis par le framework Android sont focusables par défaut. Le fait qu'un élément soit porteur ou non du focus est signalé par une modification de son apparence.
314 | L'API d'Android fournit plusieurs méthodes permettant de contrôler qu'un élément est bien focusable, ainsi que de donner le focus à un élément :
315 |
316 | * `setFocusable()` : indique que le focus pourra être pris sur l'élément
317 | * `isFocusable()` : indique si un élément peut recevoir le focus
318 | * `requestFocus()` : permet de donner le focus à un élément
319 |
320 | Si une vue ne peut pas recevoir le focus par défaut, il est possible d'utiliser l'attribut `android:focusable` avec la valeur "true" ou d'utiliser la méthode `setFocusable()` pour changer ce comportement.
321 |
322 | ### Contrôler l'ordre de lecture
323 |
324 | Lorsqu'un utilisateur navigue dans une application grâce à un contrôleur directionnel, le focus passe d'un élément de l'interface à l'autre selon un ordre déterminé par un algorithme qui cherche l'élément le plus proche dans la direction souhaitée. Dans certains cas, l'ordre calculé par cet algorithme peut ne pas être cohérent avec la logique de l'application. Pour contourner ce problème, il est possible de définir des relations entre les différents éléments. Les attributs `android:nextFocusDown` (respectivement `android:nextFocusUp`, `android:nextFocusLeft` et `android:nextFocusRight`) permettent de définir le prochain élément qui recevra le focus lorsque l'utilisateur se déplacera vers le bas (respectivement vers le haut, à gauche et à droite).
325 |
326 | Exemple :
327 | ```xml
328 |
330 |
333 |
338 |
339 | ```
340 |
341 | Cette technique peut par exemple s'appliquer pour faire en sorte que le focus décrive un cercle autour d'un ensemble d'éléments constituant une horloge : à 12h, on souhaite passer à 1h en appuyant sur "droite" ou "bas" et à 11h en appuyant sur "gauche" ou "bas". On aura des relations du type :
342 | ```xml
343 |