Semantics

Compatibilité
Date révision
30 mars 2023
Publié le
24 juil. 2018
Flutter
v 3.13.x
Dart
v 3.1.x

Avant-propos

Si vous lisez un code lié à Flutter, vous remarquerez parfois l'utilisation de Semantics ou SemanticsConfiguration mais la documentation officielle en dit très peu sur ce sujet intéressant.

Cet article est une introduction au sujet et montre combien il est important et intéressant pour votre application de prendre cela en considération.

En bref - De quoi s'agit-il?

La documentation officielle dit ce qui suit à propos de la classe Semantics:

Un widget qui annote l'arbre des widgets avec une description de la signification des widgetsUtilisé par les outils d'accessibilité, les moteurs de recherche et d'autres logiciels d'analyse sémantique pour déterminer la signification de l'application.

Personnellement, je ne trouve pas cela très explicite. Donc, je vais utiliser mes propres mots:

En bref, la notion de Semantics est:

  • totalement optionnelle (ce qui signifie que vous pourriez vivre sans vous en soucier mais pas recommandé),
  • destinée à être utilisée en conjonction avec Android TalkBack ou iOS VoiceOver (par exemple principalement par des personnes malvoyantes)
  • destinée à être utilisée par un lecteur d'écran (= Screen Reader) qui décrira l'application sans avoir à regarder l'écran.

En lisant ceci, on peut se rendre compte à quel point cela pourrait être important si vous désirez que votre application soit aussi utilisable par les personnes malvoyantes...

Comment est-ce implémenté dans Flutter?

Lorsque Flutter restitue, construit l'arborescence des Widgets, il maintient également un second arbre, appelé Semantics Tree, qui est utilisé par la technologie d'assistance de périphérique mobile (Android TalkBack ou iOS VoiceOver).

Chaque nœud de cet Semantics Tree est un *SemanticsNode qui pourrait correspondre à un ou à un groupe de Widgets.

Chaque SemanticsNode est lié à une SemanticsConfiguration, une série de propriétés qui indiquent à la technologie d'assistance du périphérique mobile comment:

  • décrire le noeud
  • se comporter avec le noeud

SemanticsConfiguration

Décrit les informations sémantiques associées à un SemanticsNode. Voici quelques-unes des propriétés (pour une liste exhaustive, veuillez vous référer à la documentation officielle).

NomDescription
reducedValuela valeur qui résultera de l'exécution d'une action diminution (par exemple, un Slider)
increaseValuela valeur qui résultera de l'exécution d'une action increase (par exemple, un Slider)
isButtonle noeud est-il un bouton ou non
isCheckedle noeud est-il une sorte de case à cocher, est-il coché ou non
isEnabledle noeud est-il activé ou non
isFocusedle noeud est-il actif pour l'introduction d'une information par l'utilisateur
isHeaderle noeud est-il un en-tête
isSelectedle noeud est-il sélectionné
isTextFieldle noeud est-il un champ de texte
indicebrève description du résultat de l'exécution d'une action sur ce noeud
étiquettedescription du noeud
valeurdescription textuelle de la valeur

Widgets automatiquement liés à une Sémantique par Flutter

La plupart des Widgets Flutter sont implicitement liés à un Semantics car ils peuvent tous être utilisés directement ou indirectement par le moteur Screen Reader.

Pour illustrer ceci, voici un extrait du code source Flutter associé à un Button:



class _RawMaterialButtonState extends State<RawMaterialButton> {

  ...

  
  Widget build(BuildContext context) {

    ...

    return Semantics(
      container: true,
      button: true,
      enabled: widget.enabled,
      child: ConstrainedBox(
        constraints: widget.constraints,
        child: Material(
          ...
        ),
      ),
    );
  }
}

Comment définir une sémantique?

Parfois, il peut être intéressant de définir (= donner une sémantique) une partie de l'écran afin qu'elle puisse être décrite par la technologie d'assistance des appareils mobiles.

Dans ce cas, utilisez simplement l'un des Widgets suivants comme conteneur de vos sous-widgets:

  • Semanticsquand vous voulez décrire seulement 1 Widget particulier

  • MergeSemanticsquand vous voulez décrire un groupe de Widgets. Dans ce cas, les différentes Semantics qui seront définies dans le sous-arbre de ce noeud seront fusionnées en une seule Sémantique. Cela pourrait être très utile pour regrouper la sémantique, cependant, en cas de conflit sémantique, le résultat peut être absurde.

Single Semantics

La classe à utiliser pour définir une sémantique est Semantics. Cette classe possède 2 constructeurs: un verbeux ou un concis.

Voici les deux façons de définir une sémantique, l'explication suit:




Widget build(BuildContext context){
  bool toBeMergedWithAncestors = false;
  bool allowDescendantsToAddSemantics = false;

  return Semantics(
    container: toBeMergedWithAncestors,
    explicitChildNodes: allowDescendantsToAddSemantics,
    ...(list of all properties)...

    child: ...
  );
}


Widget build(BuildContext context){
  SemanticsProperties properties = SemanticsProperties(...);
  bool isContainer = toBeMergedWithAncestors;
  bool explicitChildNodes = allowDescendantsToAddSemantics;

  return Semantics.fromProperties(
    container: isContainer,
    explicitChildNodes: explicitChildNodes,
    properties: properties,
    child: ...
  );
}

NomPar défautDescription
containerfauxSi la valeur est vraie (=true) un nouveau SemanticsNode sera ajouté à l'arborescence Semantics, permettant à cette sémantique de ne pas être fusionnée avec la sémantique des ancêtres. Si la valeur est false, cette sémantique sera fusionnée avec la sémantique des ancêtres
explicitChildNodesfauxindique si les descendants de ce widget sont autorisés à ajouter des informations sémantiques au SemanticsNode de ce widget

Comment ne pas avoir une sémantique?

Parfois, il pourrait y avoir des cas où vous n'auriez pas besoin de sémantique du tout. Cela pourrait être le cas pour des parties de l'écran qui ne sont que décoratives, pas importantes pour l'utilisateur.

Dans ce cas, vous devez utiliser la classe ExcludeSemantics pour exclure la sémantique de tous les descendants de ce widget. Sa syntaxe est la suivante:




Widget build(BuildContext context){
  bool alsoExcludeThisWidget = true;

  return ExcludeSemantics(
    excluding: alsoExcludeThisWidget,
    child: ...
  );
}

La propriété excluding (par défaut: true) indique au système si vous souhaitez également que ce Widget soit également exclu de l'arborescence Sémantique.

Comment regrouper les widgets en une seule sémantique?

Dans certaines circonstances, vous pourriez également vouloir regrouper toutes les sémantiques d'un ensemble de Widgets.

Un exemple de base d'un tel cas pourrait être un bloc visuel composé d'un Label et d'un Checkbox, chacun définissant sa propre sémantique. Il serait préférable que si l'utilisateur appuie sur le bloc, la technologie d'assistance du dispositif mobile fournisse une assistance liée au groupe plutôt qu'à chaque widget du groupe.

Dans ce cas, vous devez utiliser la classe MergeSemantics.

AVERTISSEMENT

Soyez très prudents lorsque vous voulez fusionner la sémantique, car si vous avez des sémantiques conflictuelles, cela peut devenir absurde pour l'utilisateur. Par exemple, si vous avez un bloc composé de plusieurs cases à cocher, chacune d'entre elles ayant des statuts différents (cochée et non cochée), le statut Sémantique résultant sera coché, induisant l'utilisateur en erreur.

Comment déboguer la sémantique?

Enfin, si vous souhaitez déboguer la sémantique de votre application, vous pouvez définir la propriété showSemanticsDebugger de votre MaterialApp sur true. Cela forcera Flutter à générer une couche en superposition pour visualiser l'arbre sémantique.



void main(){
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  // This widget is the root of your application.
  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: Text('My Semantics Test Application'),
      showSemanticsDebugger: true,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: FirstScreen(),
    );
  }
}

Conclusions

Comme la documentation officielle n'est pas encore très verbeuse sur ce sujet, je voulais simplement partager ma compréhension avec vous.

J'espère que cette introduction a souligné le fait qu'il est important de considérer la Sémantique si vous voulez mettre une application en production un jour, car les utilisateurs mobiles peuvent activer la technologie d'assistance de l'appareil mobile de leur téléphone et utiliser votre application. Si votre application n'est pas prête pour cette technologie, il pourrait y avoir des risques qu'elle ne puisse pas être utilisée par cette population d'utilisateurs.

Restez à l'écoute pour les prochains articles et bon codage.

0 Commentaires
Soyez le premier à faire un commentaire...
© 2024 - Flutteris
email: info@flutteris.com

Flutteris



Quand l'excellence rencontre l'innovation
"votre satisfaction est notre priorité"

© 2024 - Flutteris
email: info@flutteris.com