确保应用程序能够被广泛的用户群体访问是构建高质量应用程序的重要组成部分。设计不佳的应用程序会给所有年龄段的人造成障碍。《联合国残疾人权利公约》规定了确保信息系统普遍可访问性的道德和法律义务;世界各国都强制将无障碍功能作为一项要求;公司也认识到最大化其服务可访问性的商业优势。

我们强烈建议您在发布应用程序之前,将无障碍功能检查清单作为关键标准。Flutter 致力于支持开发者使其应用程序更具可访问性,除了底层操作系统提供的支持外,还包括对无障碍功能的一流框架支持,包括:

大字体
以用户指定的字体大小渲染文本组件
屏幕阅读器
传达关于 UI 内容的语音反馈
足够的对比度
以具有足够对比度的颜色渲染组件

这些功能的详细信息将在下面讨论。

检查无障碍支持

#

除了测试这些特定主题外,我们还建议使用自动化无障碍扫描器

  • 对于 Android

    1. 安装适用于 Android 的无障碍扫描器
    2. Android 设置 > 无障碍功能 > 无障碍扫描器 > 打开中启用无障碍扫描器
    3. 导航到无障碍扫描器“复选框”图标按钮以启动扫描
  • 对于 iOS

    1. 在 Xcode 中打开 Flutter 应用程序的iOS文件夹
    2. 选择模拟器作为目标,然后点击运行按钮
    3. 在 Xcode 中,选择Xcode > 打开开发者工具 > 无障碍检查器
    4. 在无障碍检查器中,选择检查 > 启用指向检查,然后选择正在运行的 Flutter 应用程序中的各种用户界面元素,以检查其无障碍属性
    5. 在无障碍检查器中,选择工具栏中的审计,然后选择运行审计以获取潜在问题的报告
  • 对于 Web

    1. 打开 Chrome DevTools(或其他浏览器中的类似工具)
    2. 检查包含 Flutter 生成的 ARIA 属性的 HTML 树。
    3. 在 Chrome 中,“Elements”选项卡有一个“Accessibility”子选项卡,可用于检查导出到语义树的数据

大字体

#

Android 和 iOS 都包含用于配置应用程序所需字体大小的系统设置。Flutter 文本组件在确定字体大小时会遵循此操作系统设置。

字体大小由 Flutter 根据操作系统设置自动计算。但是,作为开发者,您应该确保您的布局有足够的空间在字体大小增加时渲染其所有内容。例如,您可以在配置为使用最大字体设置的小屏幕设备上测试应用程序的所有部分。

示例

#

以下两个截图显示了使用默认 iOS 字体设置和在 iOS 无障碍设置中选择最大字体设置时渲染的标准 Flutter 应用程序模板。

Default font setting
默认字体设置
Largest accessibility font setting
最大无障碍字体设置

屏幕阅读器

#

对于移动设备,屏幕阅读器(TalkBackVoiceOver)使视障用户能够获得关于屏幕内容的语音反馈,并通过移动设备上的手势和桌面上的键盘快捷键与 UI 交互。在您的移动设备上打开 VoiceOver 或 TalkBack,并在您的应用程序中导航。

要打开设备上的屏幕阅读器,请完成以下步骤

  1. 在您的设备上,打开设置
  2. 选择无障碍功能,然后选择TalkBack
  3. 打开或关闭“使用 TalkBack”。
  4. 选择确定。

要了解如何查找和自定义 Android 的无障碍功能,请观看以下视频。

在新标签页中观看 YouTube 视频:“自定义 Pixel 和 Android 无障碍功能”

  1. 在您的设备上,打开设置 > 无障碍功能 > VoiceOver
  2. 打开或关闭 VoiceOver 设置

要了解如何查找和自定义 iOS 无障碍功能,请观看以下视频。

在新标签页中观看 YouTube 视频:“如何使用 VoiceOver 导航您的 iPhone 或 iPad”

对于 Web,目前支持以下屏幕阅读器

移动浏览器

  • iOS - VoiceOver
  • Android - TalkBack

桌面浏览器

  • macOS - VoiceOver
  • Windows - JAWs & NVDA

Web 端屏幕阅读器用户必须切换“启用无障碍功能”按钮来构建语义树。如果您使用此 API 以编程方式为您的应用程序自动启用无障碍功能,则用户可以跳过此步骤

dart
import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';

void main() {
  runApp(const MyApp());
  SemanticsBinding.instance.ensureSemantics();
}

Windows 自带一个名为 Narrator 的屏幕阅读器,但一些开发者推荐使用更流行的 NVDA 屏幕阅读器。要了解如何使用 NVDA 测试 Windows 应用程序,请查看面向前端开发人员的屏幕阅读器 101 (Windows)

在 Mac 上,您可以使用 macOS 中包含的 VoiceOver 桌面版。

在新标签页中观看 YouTube 视频:“屏幕阅读器基础知识:VoiceOver”

在 Linux 上,一个流行的屏幕阅读器名为 Orca。它随某些发行版预装,并可在apt等包存储库中获得。要了解如何使用 Orca,请查看在 Gnome 桌面中使用 Orca 屏幕阅读器入门


观看以下视频演示,了解 Victor Tsaran 如何使用 VoiceOver 与现已存档的Flutter Gallery Web 应用程序。

Flutter 的标准组件会自动生成一个无障碍树。但是,如果您的应用程序需要不同的东西,可以使用Semantics组件进行自定义。

当您的应用程序中有需要特定语音朗读的文本时,通过调用TextSpan.locale告知屏幕阅读器使用哪种语音。请注意,MaterialApp.localeLocalizations.override不会影响屏幕阅读器使用的语音。通常,屏幕阅读器会使用系统语音,除非您使用TextSpan.locale明确设置。

足够的对比度

#

足够的颜色对比度使文本和图像更易于阅读。除了使有各种视力障碍的用户受益外,足够的颜色对比度还有助于所有用户在极端光照条件下(例如在阳光直射下或在低亮度显示器上)查看界面。

W3C 建议

  • 小文本(常规 18 磅以下或粗体 14 磅以下)至少 4.5:1
  • 大文本(常规 18 磅及以上或粗体 14 磅及以上)至少 3.0:1

在构建时考虑无障碍功能

#

确保您的应用程序能够被所有人使用意味着从一开始就将无障碍功能融入其中。对于某些应用程序来说,这说起来容易做起来难。在下面的视频中,我们的两位工程师将一个无障碍功能糟糕的移动应用程序变成了一个利用 Flutter 内置组件提供显著更具无障碍性的体验的应用程序。

在新标签页中观看 YouTube 视频:“构建考虑无障碍功能的 Flutter 应用程序”

通过语义角色增强无障碍功能

#

什么是语义角色?

#

语义角色定义了 UI 元素的用途,帮助屏幕阅读器和其他辅助工具有效地解释和呈现您的应用程序给用户。例如,一个角色可以指示一个组件是按钮、链接、标题、滑块,还是表格的一部分。

虽然 Flutter 的标准组件通常会自动提供这些语义,但一个没有明确定义角色的自定义组件对于屏幕阅读器用户来说可能是无法理解的。

通过分配适当的角色,您可以确保

  • 屏幕阅读器可以正确地宣布元素的类型和用途。
  • 用户可以使用辅助技术更有效地导航您的应用程序。
  • 您的应用程序符合 Web 无障碍标准,提高了可用性。

在 Flutter for web 中使用SemanticsRole

#

Flutter 提供了带有SemanticsRole枚举Semantics组件,允许开发者为其组件分配特定的角色。当您的 Flutter web 应用程序渲染时,这些 Flutter 特定的角色会转换为网页 HTML 结构中相应的 ARIA 角色。

1. 来自标准组件的自动语义

许多标准 Flutter 组件,如TabBarMenuAnchorTable,会自动包含语义信息及其角色。只要可能,优先使用这些标准组件,因为它们开箱即用地处理了许多无障碍方面的问题。

2. 显式添加或覆盖角色

对于自定义组件或当默认语义不足时,使用Semantics组件定义角色

这是一个如何显式定义列表及其项的示例

dart
import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';


class MyCustomListWidget extends StatelessWidget {
  const MyCustomListWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // This example shows how to explicitly assign list and listitem roles
    // when building a custom list structure. 
    return Semantics(
      role: SemanticsRole.list,
      explicitChildNodes: true,
      child: Column( 
        children: <Widget>[
          Semantics(
            role: SemanticsRole.listItem, 
            child: const Padding(
              padding: EdgeInsets.all(8.0),
              child: Text('Content of the first custom list item.'),
            ),
          ),
          Semantics(
            role: SemanticsRole.listItem, 
            child: const Padding(
              padding: EdgeInsets.all(8.0),
              child: Text('Content of the second custom list item.'),
            ),
          ),
        ],
      ),
    );
  }
}

在移动设备上测试无障碍功能

#

使用 Flutter 的无障碍指南 API测试您的应用程序。此 API 检查您的应用程序 UI 是否符合 Flutter 的无障碍建议。这些建议涵盖了文本对比度、目标大小和目标标签。

以下代码片段显示了如何在名为AccessibleApp的示例组件上使用指南 API

test/a11y_test.dart
dart
import 'package:flutter_test/flutter_test.dart';
import 'package:your_accessible_app/main.dart';

void main() {
  testWidgets('Follows a11y guidelines', (tester) async {
    final SemanticsHandle handle = tester.ensureSemantics();
    await tester.pumpWidget(const AccessibleApp());

    // Checks that tappable nodes have a minimum size of 48 by 48 pixels
    // for Android.
    await expectLater(tester, meetsGuideline(androidTapTargetGuideline));

    // Checks that tappable nodes have a minimum size of 44 by 44 pixels
    // for iOS.
    await expectLater(tester, meetsGuideline(iOSTapTargetGuideline));

    // Checks that touch targets with a tap or long press action are labeled.
    await expectLater(tester, meetsGuideline(labeledTapTargetGuideline));

    // Checks whether semantic nodes meet the minimum text contrast levels.
    // The recommended text contrast is 3:1 for larger text
    // (18 point and above regular).
    await expectLater(tester, meetsGuideline(textContrastGuideline));
    handle.dispose();
  });
}

要尝试这些测试,请在您在编写您的第一个 Flutter 应用程序代码实验室中创建的应用程序上运行它们。该应用程序主屏幕上的每个按钮都作为一个可点击的目标,文本以 18 磅字体渲染。

您可以将指南 API 测试与其他组件测试一起添加,或者在单独的文件中添加,例如此示例中的test/a11y_test.dart

在 Web 端测试无障碍功能

#

您可以使用以下命令行标志在 profile 和 release 模式下通过可视化为您的 Web 应用程序创建的语义节点来调试无障碍功能

flutter run -d chrome --profile --dart-define=FLUTTER_WEB_DEBUG_SHOW_SEMANTICS=true

激活该标志后,语义节点会显示在组件上方;您可以验证语义元素是否放置在应有的位置。如果语义节点放置不正确,请提交错误报告

无障碍功能发布清单

#

以下是您在准备发布应用程序时需要考虑的一些非详尽列表。

  • 主动交互。确保所有主动交互都能做些事情。任何可以按下的按钮在按下时都应该做些事情。例如,如果您为onPressed事件设置了一个无操作回调,请将其更改为在屏幕上显示一个SnackBar,解释您刚刚按下了哪个控件。
  • 屏幕阅读器测试。当您点击页面上的所有控件时,屏幕阅读器应该能够描述它们,并且描述应该清晰易懂。使用TalkBack (Android) 和VoiceOver (iOS) 测试您的应用程序。
  • 对比度。我们鼓励您在控件或文本与背景之间保持至少 4.5:1 的对比度,禁用组件除外。图像也应该经过检查以确保足够的对比度。
  • 上下文切换。在输入信息时,不应有任何东西自动改变用户的上下文。通常,组件应避免在没有某种确认操作的情况下改变用户的上下文。
  • 可点击目标。所有可点击目标都应至少为 48x48 像素。
  • 错误。重要的操作应该能够撤销。在显示错误的字段中,如果可能,建议进行更正。
  • 色觉缺陷测试。控件在色盲和灰度模式下应可用和可读。
  • 缩放因子。UI 在文本大小和显示缩放的非常大缩放因子下应保持可读和可用。

了解更多

#

要了解更多关于 Flutter 和无障碍功能的信息,请查看社区成员撰写的以下文章