Flutter Semantics 控件

原文链接:https://www.didierboelens.com/2018/07/semantics/

这篇文章主要用来解释 Semantics 组件的作用,是译文 内容非原创

前言

如果你看过一些有关于Flutter的内容,你有时注意到使用了 Semantics 或者 SemanticsConfiguration 组件,但是在官方文档中有关这些内容的叙述并不多。本文是对这个主题的介绍,并且展示考虑在您的 APP 中使用这类组件的重要性和一些有趣的内容。

简而言之——这是什么?

在官方文档中是这样介绍 Semantics 类的:

A widget that annotates the widget tree with a description of the meaning of the widgets Used by accessibility tools, search engines, and other semantic analysis software to determine the meaning of the application.

通过对控件含义的描述信息注释控件树的一个控件,可通过可访问性工具,搜索引擎和其他语义化分析的软件确定应用程序的含义。

简而言之:

  • 可选择性。这意味着你可以完全不关心它的使用,但是不建议
  • 主要用于在 Android TalkBack 或者 iOS VoiceOver 使用,例如视障人士的使用
  • 主要用于屏幕阅读器的使用,它将描述这个应用程序而不需要查看屏幕

阅读到这里,如果你的应用程序主要用于视障人士,这是多么的重要。

如何在 Flutter 中使用

当在 Flutter 中渲染 Widget 树时,它还会维护第二个树,称为 Semantics Tree。它通常被用在移动辅助设备上,例如Android TalkBack 或者 iOS VoiceOver 。

Semantics Tree的每一个节点都是 SemanticsNode,它可能对应一个或者一组Widgets。

每个 SemanticsNode 都链接到一个 SemanticsConfiguration, 通过一系列的属性告诉移动辅助设备: 如何描述节点、 如何配合节点的工作。

SemanticsConfiguration

描述与之相关联的 SemanticsConfiguration 的语义信息,一下是部分属性(详情参阅 官方文档

名称 描述
decreasedValue 执行减少操作所产生的值(例如滑块)
increasedValue 执行增加操作所产生的值(例如滑块)
isButton 这个节点是不是按钮
isChecked 是否是复选框,是否被选中
isEnabled 是否允许使用
isFocused 是否获得到焦点
isHeader 是否是Header节点
isSelected 是否是选择节点
isTextField 是否是text field节点
hint 对在此节点上执行操作的结果的简述
label 节点的描述
value value值的文本描述

隐式带有语义的Flutter小部件

大多数Flutter小部件都隐式的定义了 Semantics ,因为他们可能都直接或者间接的在 Screen Reader 引擎中被使用。

为了说明这一点,下面是一段摘录自 Flutter 源码的关于 Button 的部分:

class _RawMaterialButtonState extends State<RawMaterialButton> {

  ...

  @override
  Widget build(BuildContext context) {

    ...

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

如何定义Semantics

有时定义屏幕的一部分便于移动设备辅助技术进行描述,是十分有趣的。

在这些情况下,只需使用以下部件作为字部件的容器:

  • Semantics, 只想描述一个特定的小部件的语义使用。
  • MergeSemantics, 当描述使用一组小部件时使用。在这种情况,定义在这个子树行上的节点的语义将会合并为一个语义。这对于重组语义这是十分有用的,然而在语义冲突的情况,结果可能是无意义的。

单个Semantics

用于定义语义的类是Semantics。这个类有2个构造函数:一个是冗长的,一个是简洁的。
下面是定义语义的两种方法,解释如下:

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

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

    child: ...
  );
}

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

  return new Semantics.fromProperties(
    container: isContainer,
    explicitChildNodes: explicitChildNodes,
    properties: properties,
    child: ...
  );
}
名称 默认值 描述
container false 如果该值为true,将向语义树添加一个新的SemanticsNode,从而使该语义不会与祖先的语义合并。如果值为假,则此语义将与祖先的语义合并
explicitChildNodes false 表明是否允许此小部件的后代向该小部件的SemanticsNode添加语义信息

如何没有语义?

有时候,屏幕上只具有装饰性、对用户不重要的部分,您可能根本不需要任何语义。

在这种情况下,您需要使用 ExcludeSemantics 类来移除这个小部件的所有后代的语义。其语法如下:

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

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

exclude属性(默认值:true)告诉系统您是否也希望这个小部件被排除在语义树之外。

如何将小部件语义重组成单一语义?

在某些情况下,您可能还希望重组一组小部件的所有语义成单一语义。
例如,在 一个由 label 和 checkbox(复选框) 组成的 功能块中,且每个复选框定义自己的语义的情况下,如果用户按下该块,移动设备辅助技术将提供与整个功能块相关的帮助信息,而不是功能块中的每个小部件的信息。

在这种情况下你应该使用 MergeSemantics 类.

WARNING
Be very careful when you want to merge the Semantics since if you have any conflicting Semantics, this might result in becoming nonsensical for the user. For example, if you have a block made up of several checkboxes, each of them having different statuses (checked and not checked), the resulting Semantics status will be checked, misleading the user.

当您想合并语义时要非常小心,因为如果您有任何冲突的语义,这可能会导致语义对用户来说变得毫无意义。例如,如果您有一个由几个复选框组成的块,每个复选框都有不同的状态(选中和未选中),那么结果的语义状态将被选中,从而误导用户。

如何调试语义?

最后,如果希望调试应用程序的语义,可以将MaterialApp的showSemanticsDebugger 属性设置 为true。这将强制Flutter生成一个可视化语义树。

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

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

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

总结

如果您希望某天发布应用程序,那么考虑语义非常重要,因为移动用户可能会打开他们的手机的移动设备辅助技术并使用您的应用程序。如果您的应用程序还没有为这项技术做好准备,则可能存在无法使用该技术的风险。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容