专栏首页JarvanMo的IT专栏Flutter: Semantics控件

Flutter: Semantics控件

本来为译文,原文请戳这里

这篇文章解释了Flutter中Semantics的概念。 难度:入门级。

前言 如果你读过有关于Flutter的代码,那么你有时候你会注意到Semantics或者SemanticsConfiguration,但官方文档却对这个很有趣的话题却没有很多的资料。 这篇文章是对这个话题的介绍。与此同时也会向您展示您的应用是否会考虑使用Semantics,这取决于其重要性和兴趣度。

简而言之-这是什么东东? 官方文档Semantics类介绍如下:

一个用来描述控件树中控件含义的控件,这些描述被可访问性工具,搜索引擎或者其他其他语义分析软件使用,以确定应用程序的含义。

我个人认为这段解释云里雾里。 所以用我自己的话说就是:

言简意骇,Semantics的概念是:

  1. 完全可选(这意味着你可以完全不关心这个控件,但这并不推荐), 2.意味着可以与Android TalkBack****或iOS VoiceOver****一起使用(例如主要由视障人士使用), 3.意味着可以由屏幕阅读器(Screen Reader)使用,它会描述应用程序而无需查看屏幕。

通过阅读本文,我们可以意识到,如果您将应用程序定位为视障人士也可以使用,这将是多么重要...

在Flutter中他是怎么实现的? 当Flutter渲染控件树时,它还会维护第二个控件树,称为Semantics Tree,它被移动设备辅助技术(Android TalkBackiOS VoiceOver)所使用。

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

每个SemanticsNode都会对应一个SemanticsConfiguration,这是一组属性,这将告诉移动设备辅助技术如何:

  1. 描述节点
  2. 与节点一起行动

SemanticsConfiguration 描述与之相关的SemanticsNode的语义信息。下面将列举其中部分属性(更详细的请查阅官方文档)。

名称

描述

decreasedValue

一个执行decrease动作的返回值,如Slider

increasedValue

一个执行increased动作的返回值,如Slider

isButton

该节点是否是Button

isChecked

该节点是一种 CheckBox,是否被选中

isEnabled

该节点是否可用

isFocused

该节点是否持有用户的焦点

isHeader

该节点是否为Header

isSelected

该节点是否被选中

isTextField

该节点是否文本字段

hint

在此节点上执行操作的结果的简要说明

label

节点描述

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中。这对于重新组合语义非常有用,但是,如果语义冲突,结果可能是无意义的。

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

@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添加到Semantics树中,从而不允许此Semantics与父Semantics合并。 如果值为false,则此语义将与父Semantics合并

explicitChildNodes

false

该控件的子控件是否允许将Semantics信息添加到该控件的SemanticsNode中

如何不使用Semantics

有时时候可能会出现根本不需要任何Semantics的情况。 这可能是屏幕的一些部分,它们只是装饰性的,对用户来说并不重要。 这种情况下,您需要使用ExcludeSemantics来去除某个控件及其子控件的Semantics。语法如下:

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

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

exclude属性(默认值:true)告诉系统您是否也希望从Semantics树中排除此Widget。

如何将控件重组成一个Semantics? 在某些情况下,您可能还想重新组合一组控件的所有Semantics。 这种情况的一个基本示例可能是由Label和Checkbox组成的可视块,每个都定义了自己的Semantics。 最好的是,如果用户按下该块,则移动设备辅助技术将提供与该组相关的辅助功,而不是提供该组的每个Widget的辅助信息。

这种情况下,你应该使用MergeSemantics

注意 当你想要合并Semantics时要非常小心,因为如果你有任何冲突的Semantics,这对用户来可能说是荒谬的。 例如,如果您有一个由多个复选框组成的块,每个复选框具有不同的状态(已选中且未选中),则将检查生成的语义状态,从而误导用户。

如何调试Semantics 最后,如果要调试app中的Semantics,可以将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(),
    );
  }
}

结论 由于官方文档在这方面的介绍并不是很详细,我只想与您分享我的理解。

我希望这一介绍突出了这样一个事实,即如果你想有一天发布一个应用程序,考虑语义是很重要的,因为移动用户可能会打开手机的移动设备辅助技术并使用你的应用程序。 如果您的应用程序尚未准备好使用此技术,则可能存在无法使用的风险。 我希望通过本文可以让您意识到如果有一天您想发布一个app,考虑使用Semantics是很重要的,因为手机用户可能打开移动设备辅助技术并使用你的app。 如果您的app尚未准备好使用此技术,则可能存在无法使用的风险。

开心写代码~

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Flutter: Semantics控件

    如果你读过有关于Flutter的代码,那么你有时候你会注意到Semantics或者SemanticsConfiguration,但官方文档却对这个很有趣的话题却...

    JarvanMo
  • [译]Flutter Platform Channels(二)

    Method channels是platform channels的一种,用于调用Dart和Java / Kotlin或Objective-C / Swift中...

    JarvanMo
  • 为Gradle设置镜像,解决jcenter依赖无法下载或者下载过慢问题

    这其实是一个烂大街的教程了。百度上一堆解决方案,好用的没几个。所以决定温习一下,因为最近写了几个Flutter插件,有很人多表示无法下载Android依赖,于是...

    JarvanMo
  • 自定义View简单使用

    当我们开发中遇到Android原生的组件无法满足需求时,这时候就应该自定义View来满足这些特殊的组件需求。 一、概述 很多初入Android开...

    分享达人秀
  • Flutter布局模型之层叠定位

    Stack控件的每一个子控件都是定位或不定位,定位的子控件是被Positioned控件包裹的。Stack控件本身包含所有不定位的子控件,其根据alignment...

    砸漏
  • EasyUI中那些不容易被发现的坑——EasyUI重复请求2次的问题

    问题控件:datagrid、combobox、所有能设置url属性的控件 问题版本:1.4.4、1.4.5(之前的版本没测) 问题如图: ? 重复请求2次,错误...

    Java中文社群-磊哥
  • 给彦女王生成一副蒙太奇画像

    大家好呀,前两天烈阳天道1上映了,不知道大家看没看呢,里面还有一小段彦穿越虫洞与猴哥相遇的画面,彦女王啊啊啊~~

    周旋
  • 第 12 章 动态内存

    用户1653704
  • Qt编写自定义控件20-自定义饼图

    上次在写可视化数据大屏电子看板项目的时候,为了逐步移除对QChart的依赖(主要是因为QChart真的太垃圾了,是所有Qt的模块中源码最烂的一个,看过源码的人没...

    feiyangqingyun
  • SQL and R

    R平台及编程语言支持浩大的数据科学技术,他拥有几十年的的历史和超过7000个包,这挂在CRAN的包纷杂的让你无法决定从哪里入手。R-Basics和Visua...

    小莹莹

扫码关注云+社区

领取腾讯云代金券