L'accessibilité dans iOS 27 : applications de lecture et contrôles personnalisés
Lire un contenu long est un problème différent de celui de naviguer dans une interface : le but est de se déplacer avec fluidité à travers le texte, et non de sauter d’un contrôle à l’autre. Les deux sessions WWDC26 consacrées à l’accessibilité se répartissent précisément le long de cette ligne de partage : l’une porte sur la surface de lecture, l’autre sur les contrôles qui l’entourent.
Cette distinction compte parce que les correctifs diffèrent par nature. Les défaillances d’une application de lecture relèvent de la continuité : un texte qui refuse de se relier d’un paragraphe à l’autre, une lecture intégrale qui s’arrête au bas d’une page. Celles d’un contrôle personnalisé relèvent de la traduction : un geste qui transmet tout visuellement et rien à VoiceOver. iOS 27 livre des API visant ces deux fronts, et l’une d’elles, accessibilityLinkedGroup, est nouvelle cette année.
TL;DR
- Les applications de lecture devraient d’abord se tourner vers les vues de texte du système.
UITextView,TextEditoretTextavec sélection activée adoptent le protocoleUITextInputet obtiennent gratuitement la navigation par ligne, mot et caractère ainsi que la sélection1. - Lorsque la mise en page impose des éléments de texte distincts, reliez-les pour que VoiceOver puisse franchir la jointure. iOS 18 a introduit
accessibilityNextTextNavigationElement/accessibilityPreviousTextNavigationElement; iOS 27 ajoute le modificateur SwiftUIaccessibilityLinkedGrouppour le même effet1. - Pour un contenu paginé, le trait
causesPageTurnassocié àaccessibilityScrollfait avancer automatiquement les pages dans Speak Screen et VoiceOver pendant une lecture intégrale1. - Le texte rendu sur mesure (pages numérisées, typographie avancée) perd tout cela. Adopter
UITextInputdans son intégralité le restaure : la géométrie viaselectionRects, les sous-chaînes viatextInRangeet un tokeniseur pour la navigation par ligne, mot et caractère1. - Les contrôles personnalisés suivent quatre principes directeurs : objet, valeur, actions, retour. Les outils sont
accessibilityLabel/accessibilityValue, le trait.adjustableavecaccessibilityAdjustableAction, des actions personnalisées pour les contrôles à plusieurs axes, et le toucher direct (allowsDirectInteraction) pour les surfaces riches en gestes2.
Applications de lecture : relier le texte que la mise en page a séparé
La session sur les applications de lecture s’articule autour d’une contrainte d’une simplicité trompeuse. L’application de guide de voyage du présentateur utilise une UITextView distincte pour chaque paragraphe parce que la mise en page l’exigeait, plutôt qu’une seule vue contenant toute la page1. Chaque vue de texte est accessible isolément. Le problème surgit à la frontière entre elles.
Le présentateur fixe trois objectifs à l’application : une navigation textuelle granulaire pour que VoiceOver et Speak Screen se déplacent avec fluidité dans le texte, une expérience de lecture continue sans interruption, et une sélection de texte complète1. Le reste de la session est un tour d’horizon de l’API qui satisfait chacun d’eux.
Pour la navigation entre des vues distinctes, la réponse réside dans les API d’éléments de navigation textuelle introduites dans iOS 18. Pour chaque élément de texte, vous renvoyez l’élément de texte accessible suivant et précédent vers lequel VoiceOver doit se déplacer. Dans l’exemple de la session, le paragraphe 1 renvoie le paragraphe 2 depuis son accessibilityNextTextNavigationElement, et le paragraphe 2 renvoie le paragraphe 1 depuis son accessibilityPreviousTextNavigationElement1. Une fois branché, VoiceOver dépasse la fin d’un paragraphe et passe à la première ligne du suivant au lieu de jouer le son d’impasse.
L’ajout d’iOS 27 se trouve dans SwiftUI. Comme le dit le présentateur, à partir d’iOS 27, relier plusieurs éléments de texte à l’aide du modificateur accessibilityLinkedGroup produit le même effet1. Vous donnez aux éléments reliés le même id et le même namespace, et ils héritent du comportement de navigation textuelle entre éléments sans la gestion manuelle du suivant et du précédent. AppKit reçoit l’équivalent accessibilitySharedTextUIElements pour le même résultat sur Mac1. L’article Ce dont SwiftUI est fait de la grappe explique comment des modificateurs SwiftUI comme celui-ci se résolvent jusqu’à l’arbre d’accessibilité sous-jacent.
La continuité est le deuxième objectif. Un contenu paginé requiert de balayer, et une lecture intégrale devrait ignorer les limites de page comme le fait un livre audio. Dans la session, Speak Screen s’arrête net au bas de la première page jusqu’à ce que le présentateur applique le trait causesPageTurn au dernier paragraphe de chaque page. Associé à accessibilityScroll, Speak Screen et VoiceOver défilent alors automatiquement vers la page suivante lorsqu’ils en atteignent la fin, et le trait est disponible aussi bien dans UIKit que dans SwiftUI1.
Le troisième objectif, la sélection, vient pour l’essentiel gratuitement des vues de texte du système, mais la session ajoute une touche réfléchie : une action « Enregistrer la recommandation » exposée via le rotor d’édition de VoiceOver. Le présentateur redéfinit accessibilityCustomActions sur la vue de texte du paragraphe et construit l’action personnalisée avec la catégorie d’édition, précisément pour qu’elle apparaisse dans le rotor d’édition aux côtés des opérations de sélection de texte plutôt que comme une action générique1. La consigne est explicite : utilisez la catégorie d’édition lorsqu’une action personnalisée est associée à la sélection de texte.
Lorsque vous rendez votre propre texte : UITextInput dans son intégralité
La seconde moitié de la session de lecture aborde le cas où les vues du système ne sont pas une option. Le texte personnalisé apparaît dans les applications de lecture dédiées à la typographie avancée, dans le code partagé entre applications ou dans les pages numérisées, et l’exemple du présentateur est le plus tranchant : remplacer les vues de texte du guide de voyage par des pages numérisées d’un carnet manuscrit. Le coût est total. Passer aux images fait perdre le comportement d’accessibilité que UITextView fournissait gratuitement, jusqu’à la chose la plus élémentaire : lire le texte à voix haute. VoiceOver se contente de dire « Image »1.
Le correctif consiste à adopter le protocole UITextInput, qui peut se greffer sur n’importe quel élément d’accessibilité et rendre le texte rendu ou le texte dans les images aussi accessible qu’une vue de texte standard1. Le hic, énoncé sans détour dans la session, c’est qu’il faut l’implémenter dans son entièreté pour en tirer tout le bénéfice. Le présentateur passe en revue les pièces porteuses :
- La géométrie.
selectionRectscalcule les rectangles de surlignage pour une plage donnée. À partir d’une image manuscrite, le présentateur utilise la hauteur et la largeur connues de chaque ligne pour approximer les rectangles via une fonctionselectionRectFromImagepersonnalisée, puis renvoie le tableau assemblé1. - Les sous-chaînes.
textInRangene renvoie que la portion de texte interrogée par une technologie d’assistance1. - Un tokeniseur. La navigation par ligne, phrase, mot ou caractère passe par un tokeniseur. La session crée une sous-classe du
UITextInputStringTokenizerd’UIKit pour s’adapter à la mise en page personnalisée1.
Un raffinement est explicitement facultatif. Pour que la sélection paraisse aboutie, avec poignées et surlignages, le présentateur ajoute une UITextInteraction à la vue de page et appelle le délégué de saisie lorsque la sélection change, afin que le système mette à jour le rendu visuel. La session note que cette étape n’est pas exigée par UITextInput lui-même ; elle parfait l’expérience pour égaler une vue de texte standard1. Et UITextInput se compose avec les API précédentes, de sorte que causesPageTurn et les éléments de navigation fonctionnent aussi sur du texte personnalisé.
Il y a une récompense, soulignée par la session, qu’il est facile de sous-estimer : ce travail ne sert pas seulement VoiceOver et Speak Screen. Depuis iOS 26, Accessibility Reader peut ouvrir le contenu d’une application dans un affichage réglé pour une lecture plus aisée, et les mêmes pratiques de texte accessible améliorent aussi cette expérience1.
Contrôles personnalisés : objet, valeur, actions, retour
La session sur les contrôles personnalisés s’ouvre sur un curseur SwiftUI standard et sur un argument quant à la raison de son efficacité. Vous lisez une glissière, une poignée placée à mi-course, une amorce de manipulation par glissement et un retour immédiat, le tout d’un seul coup d’œil. Personne n’a rien expliqué de tout cela. Puis la session pose la question évidente : et si quelqu’un ne peut pas voir l’écran ? VoiceOver répond en lisant « Luminosité, 50 %, ajustable », assorti d’une indication pour balayer vers le haut ou le bas, ce qui transmet les quatre mêmes choses que le visuel : l’objet, la valeur, l’action disponible et le retour à mesure que la valeur change2.
.adjustable doté d’une action ajustable.
Ces quatre mots (objet, valeur, actions, retour) sont les principes directeurs de la session, et chaque exemple y renvoie2. Le premier est un contrôle de distributeur de café : on glisse vers le haut pour plus de café, vers le bas pour moins, le niveau de remplissage représentant les onces. Avant tout travail, VoiceOver le lit comme un générique « Bouton, 6 onces », sans aucune indication sur la façon d’en modifier la valeur2. Les correctifs sont progressifs :
- Objet et valeur.
accessibilityLabelle nomme « Distributeur de café » ;accessibilityValueannonce le niveau de remplissage actuel2. - Action. Le trait
.adjustableindique à VoiceOver que le contrôle répond aux balayages vers le haut et le bas, etaccessibilityAdjustableActionfournit une closure dotée d’un paramètre de direction.incrementou.decrementpour traiter chaque cas2.
On obtient ainsi un ajustement d’une once à la fois. Pour un contrôle plus fin, la session se tourne vers le geste de passage intégré à VoiceOver : un double appui maintenu qui débute au accessibilityActivationPoint du contrôle et envoie les événements tactiles directement au contrôle à mesure que le doigt se déplace. Le présentateur règle le point d’activation pour qu’il corresponde au niveau de remplissage actuel2. Le retour pendant le passage est une petite leçon de retenue : la session ne publie une annonce que lorsque la valeur a réellement changé et qu’au moins 0,3 seconde s’est écoulée, car annoncer chaque changement serait bruyant2.
Le pavé d’égaliseur place la barre plus haut. C’est un contrôle bidimensionnel, et la session admet franchement que .adjustable est le mauvais outil, car ses actions d’incrément et de décrément ne couvrent qu’un seul axe. La réponse, ce sont les actions personnalisées : le modificateur accessibilityAction appliqué quatre fois pour « déplacer vers le haut », « déplacer vers la droite », « déplacer vers le bas » et « déplacer vers la gauche », chacune décalant un axe d’un pas fixe borné à la plage2. Contrairement à l’action ajustable, les actions personnalisées prennent en charge n’importe quelle opération que vous définissez, et elles atteignent aussi les utilisateurs de Switch Control et de Voice Control2.
Le toucher direct : quand les gestes sont l’essentiel
Le dernier exemple de la session est un contrôle de chat virtuel où l’on caresse, tapote et pince pour obtenir différentes réactions. Le passage convient mal ici, note le présentateur, car certains voudront peut-être répéter une action encore et encore ou utiliser plusieurs gestes2. Le contrôle se tourne donc vers le toucher direct.
.accessibilityDirectTouch avec .requiresActivation à un contrôle piloté par gestes, de sorte que les touchers passent directement au chat au lieu d’être interceptés par VoiceOver.
Le trait allowsDirectInteraction marque une région comme zone de toucher direct : les événements tactiles passent droit au contrôle au lieu d’être traités par VoiceOver, si bien que chaque geste pris en charge par le contrôle fonctionne2. Deux options façonnent le comportement. .requiresActivation garde le contrôle inerte jusqu’à un double appui, ce qui permet de glisser à travers l’écran sans le déclencher par mégarde, et le toucher direct reste ensuite actif jusqu’à ce que le focus quitte l’élément. .silentOnTouch maintient VoiceOver silencieux sur la région, ce qui vise les contrôles qui produisent leur propre audio que la parole de VoiceOver recouvrirait autrement2. Le chat virtuel utilise .accessibilityDirectTouch avec .requiresActivation2.
La session se clôt sur une réserve qui renoue avec l’argument de l’accessibilité comme plateforme développé dans L’accessibilité comme plateforme : tout le monde ne peut pas exécuter les gestes du toucher direct, alors exposez chaque fois que possible une autre voie, telle que des actions personnalisées, pour que les utilisateurs de Switch Control et de Voice Control accèdent aux mêmes interactions2.
Conseils d’adoption
Les deux sessions s’achèvent sur la même instruction : activez VoiceOver et auditez votre propre application. Concrètement :
- Pour une surface de lecture sur des vues de texte du système, essayez le geste de lecture intégrale, naviguez avec le rotor des lignes et sélectionnez du texte. Si une lecture intégrale s’arrête à une limite de page, adoptez
causesPageTurnavecaccessibilityScroll. Si la navigation par ligne aboutit à une impasse entre des éléments de texte distincts, reliez-les avec les API d’éléments de navigation (UIKit) ouaccessibilityLinkedGroup(SwiftUI, iOS 27)1. - Si vous rendez votre propre texte, prévoyez une adoption complète de
UITextInput, et non partielle ; le protocole est tout ou rien, et l’étape facultativeUITextInteractionest ce qui donne à la sélection un caractère natif1. - Pour tout contrôle personnalisé, parcourez les quatre principes dans l’ordre. Un utilisateur de VoiceOver peut-il savoir ce que c’est (libellé), dans quel état il se trouve (valeur), ce qu’il peut faire (trait ajustable ou actions personnalisées) et ce qui s’est passé (annonces) ? Réservez le toucher direct aux contrôles dont la valeur est le geste lui-même, et associez-le à une solution de repli non gestuelle2.
Le thème récurrent : tournez-vous d’abord vers les composants du système, et traitez la voie personnalisée comme l’exception qui exige un travail réel et complet. L’article Les trois surfaces d’une application iOS présente l’accessibilité comme une surface de premier ordre, au même titre que l’interface visible et App Intents ; ces sessions montrent ce à quoi ressemble la bonne maîtrise de cette surface pour le texte et les contrôles.
FAQ
Quelle est la nouvelle API d’accessibilité d’iOS 27 pour les applications de lecture ?
Le modificateur SwiftUI accessibilityLinkedGroup. À partir d’iOS 27, relier plusieurs éléments de texte avec le même id et le même namespace leur confère une navigation textuelle entre éléments, de sorte que VoiceOver passe de la dernière ligne d’un élément à la première ligne du suivant. C’est l’équivalent SwiftUI des API iOS 18 accessibilityNextTextNavigationElement/accessibilityPreviousTextNavigationElement et de accessibilitySharedTextUIElements d’AppKit1.
Dois-je implémenter UITextInput si j’utilise une vue de texte standard ?
Non. UITextView (UIKit), TextEditor et Text avec sélection activée (SwiftUI), ainsi que NSTextView (AppKit), adoptent déjà UITextInput et fournissent d’emblée la navigation par ligne, mot et caractère ainsi que la sélection. Vous n’adoptez UITextInput vous-même que lorsque vous rendez du texte personnalisé, comme des pages numérisées ou une typographie avancée, où ces comportements du système sont perdus1.
Quand un contrôle personnalisé doit-il utiliser le trait ajustable plutôt que des actions personnalisées ?
Utilisez le trait .adjustable avec accessibilityAdjustableAction pour des valeurs à un seul axe où l’incrément et le décrément ont du sens, comme un curseur. Utilisez des actions personnalisées (le modificateur accessibilityAction) lorsqu’un seul axe ne suffit pas, comme un pavé bidimensionnel, ou lorsque vous voulez exposer des opérations distinctes que VoiceOver lit par leur nom. Le pavé d’égaliseur de la session utilise quatre actions personnalisées (déplacer vers le haut/la droite/le bas/la gauche) précisément parce que le trait ajustable ne couvre qu’une seule direction2.
Qu’est-ce que le toucher direct et quand dois-je l’utiliser ?
Le toucher direct (le trait allowsDirectInteraction, appliqué via .accessibilityDirectTouch dans SwiftUI) marque une région pour que les touchers passent droit à votre contrôle au lieu d’être traités par VoiceOver, ce qui permet d’utiliser chaque geste pris en charge par le contrôle. Utilisez-le pour les contrôles riches en gestes où le geste de passage convient mal, et associez-le à .requiresActivation pour éviter les déclenchements accidentels. Offrez toujours une solution de repli non gestuelle, telle que des actions personnalisées, pour les personnes incapables d’exécuter les gestes du toucher direct2.
En quoi un texte accessible profite-t-il à des fonctions au-delà de VoiceOver ?
Le même travail porte ses fruits dans Speak Screen et, depuis iOS 26, dans Accessibility Reader, qui ouvre le contenu d’une application dans un affichage réglé pour une lecture plus aisée. Mettre en œuvre les pratiques de navigation textuelle, de tourne-page et de UITextInput couvertes par la session de lecture améliore ces trois expériences à partir d’un seul jeu de modifications1.
Lectures complémentaires
- L’accessibilité comme plateforme : Personal Voice, Live Speech, suivi oculaire, Music Haptics
- Ce dont SwiftUI est fait
- Les trois surfaces d’une application iOS
- La surface des widgets et des contrôles d’iOS 26
- Hub : Série Apple Ecosystem
- Guide : Développement d’agents iOS
Références
-
Apple, session WWDC26 219, « Enhance the accessibility of your reading app ». developer.apple.com/videos/play/wwdc2026/219. Source pour les vues de texte du système (
UITextView,TextEditor,Textavec sélection,NSTextView) adoptantUITextInput; les API iOS 18accessibilityNextTextNavigationElement/accessibilityPreviousTextNavigationElementet le modificateur SwiftUI iOS 27accessibilityLinkedGroup(AppKit :accessibilitySharedTextUIElements) ;causesPageTurnavecaccessibilityScroll; l’action de sélection de texte viaaccessibilityCustomActionsavec la catégorie d’édition ; l’adoption complète deUITextInputpour le texte personnalisé (selectionRects,textInRange,UITextInputStringTokenizer) plus laUITextInteractionfacultative ; et Accessibility Reader d’iOS 26. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Apple, session WWDC26 220, « Refine accessibility for custom controls ». developer.apple.com/videos/play/wwdc2026/220. Source pour les principes objet/valeur/actions/retour ; le contrôle de distributeur de café utilisant
accessibilityLabel,accessibilityValue, le trait.adjustableetaccessibilityAdjustableAction; le geste de passage auaccessibilityActivationPointavec annonces limitées (valeur changée et 0,3 seconde écoulée) ; le modificateuraccessibilityActionpour le pavé d’égaliseur ; et le toucher direct viaallowsDirectInteraction(.accessibilityDirectTouch) avec.requiresActivationet.silentOnTouchpour le contrôle de chat virtuel, ainsi que le rappel de la solution de repli non gestuelle. ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩