使用语义属性生成无障碍应用

辅助功能语义主要用于生成各种体验,使你的应用对用户具有包容性,方便其在各种环境中使用技术并满足其对 UI 的一系列需求和体验要求。 在许多情况下,针对辅助功能的法律要求会促使开发人员解决辅助功能问题。 不管怎样,建议生成具有包容性且操作方便的应用,从而使应用可以覆盖尽可能多的受众。

Web 内容辅助功能准则 (WCAG) 是面向 Web 和移动端的全球性辅助功能标准和法律基准。 这些指南介绍了使应用更易于感知、操作、理解且更加可靠的各种方式,涵盖到所有用户。

许多用户辅助功能需求都是通过用户安装的无障碍技术产品或由操作系统提供的工具和设置来满足的。 这包括屏幕阅读器、屏幕放大和高对比度设置等功能。

屏幕阅读器通常以听觉方式描述屏幕上显示的控件。 这些描述可帮助用户浏览应用,并提供对没有输入内容或文本的控件(如图像)的引用。 屏幕阅读器通常是通过触摸屏、触控板或键盘上的手势来控制。 有关启用屏幕阅读器的信息,请参阅启用屏幕阅读器

操作系统有自己的屏幕阅读器,这些阅读器有自己的独特行为和配置。 例如,大多数屏幕阅读器在控件获得焦点时会读取与控件关联的文本,从而使用户能够在浏览应用时自行定位。 但是,某些屏幕阅读器在页面显示时也会读取整个应用用户界面,使用户在尝试导航它之前能够收到页面的所有可用信息内容。

大多数屏幕阅读器会自动阅读与获得辅助功能焦点的控件关联的任何文本。 这意味着用户可以访问设置了 Text 属性的控件,例如 LabelButton。 但是,由于没有与之关联的文本,因此 ImageImageButtonActivityIndicator 和其他元素可能不在辅助功能树中。

.NET Multi-platform App UI (.NET MAUI) 支持通过两种方法提供基础平台辅助功能体验。 语义属性是在应用中提供辅助功能值的 .NET MAUI 方法,也是推荐的方法。 自动化属性是在应用中提供辅助功能值的 Xamarin.Forms 方法,已被语义属性所取代。 在这两种情况下,控件的默认辅助功能顺序与它们在 XAML 中列出或添加到布局中的顺序相同。 但是,不同的布局可能还有其他会影响辅助功能顺序的因素。 例如,StackLayout 的辅助功能顺序还基于其方向,而 Grid 的辅助功能顺序则基于其行和列排列。 有关内容排序的详细信息,请参阅 Xamarin 博客上的有意义的内容排序

注意

如果 WebView 显示一个可以访问的网站,则也可以在 .NET MAUI 应用中访问该网站。 相反,如果 WebView 显示一个无法访问的网站,则也无法在 .NET MAUI 应用中访问该网站。

语义属性

语义属性用于定义有关哪些控件应获得辅助功能焦点以及应向用户大声朗读哪些文本的信息。 语义属性是可添加到任何元素以设置基础平台辅助功能 API 的附加属性。

重要

语义属性不会尝试在每个平台上强制执行等效行为。 实际上,它们依赖于每个平台提供的辅助功能体验。

SemanticProperties 类定义以下附加属性:

  • Description,类型为 string,表示将由屏幕阅读器大声朗读的说明。 有关详细信息,请参阅 Description
  • Hint,类型为 string,类似于 Description,但提供更多上下文,例如控件的用途。 有关详细信息,请参阅提示
  • HeadingLevel,类型为 SemanticHeadingLevel,支持将元素标记为标题以组织 UI,使其更易于导航。 有关详细信息,请参阅标题级别

这些附加属性可设置平台辅助功能值,以便使屏幕阅读器可以朗读元素。 有关附加属性的详细信息,请参阅附加属性

说明

Description 附加属性表示屏幕阅读器用于读出元素的简短描述性 string。 应针对具有含义的元素设置此属性,这种含义对理解内容或与用户界面进行交互很重要。 可以在 XAML 中设置此属性:

<Image Source="dotnet_bot.png"
       SemanticProperties.Description="Cute dot net bot waving hi to you!" />

也可在 C# 中进行设置:

Image image = new Image { Source = "dotnet_bot.png" };
SemanticProperties.SetDescription(image, "Cute dot net bot waving hi to you!");

此外,SetValue 方法还可用于设置 Description 附加属性:

image.SetValue(SemanticProperties.DescriptionProperty, "Cute dot net bot waving hi to you!");

也可以在另一个元素上定义某元素的辅助功能信息。 例如,Switch 旁的 Label 可用于描述 Switch 所表示的内容。 这可以通过以下操作在 XAML 中实现:

<Label x:Name="label"
       Text="Enable dark mode: " />
<Switch SemanticProperties.Description="{Binding Source={x:Reference label} Path=Text}" />

或者,可在 C# 中设置如下:

Label label = new Label
{
    Text = "Enable dark mode: "
};
Switch mySwitch = new Switch();
SemanticProperties.SetDescription(mySwitch, label.Text);

警告

  • 避免在 Label 上设置 Description 附加属性。 这将停止屏幕阅读器正在朗读的 Text 属性。 这是因为视觉文本应与屏幕阅读器大声朗读的文本相匹配。
  • 避免在 Android 上的 EntryEditor 上设置 Description 附加属性。 这样做将使 Talkback 操作停止正常运行。 请改用 Placeholder 属性或 Hint 附加属性。
  • 在 iOS 上,如果在具有子级的任何控件上设置 Description 属性,屏幕阅读器将无法到达子级。 这是因为 iOS 不提供允许从父元素导航到子元素的辅助功能。

提示

Hint 附加属性表示一个为 Description 附加属性提供更多上下文的 string,例如控件的用途。 可以在 XAML 中设置此属性:

<Image Source="like.png"
       SemanticProperties.Description="Like"
       SemanticProperties.Hint="Like this post." />

也可在 C# 中进行设置:

Image image = new Image { Source = "like.png" };
SemanticProperties.SetDescription(image, "Like");
SemanticProperties.SetHint(image, "Like this post.");

此外,SetValue 方法也可用于设置 Hint 附加属性:

image.SetValue(SemanticProperties.HintProperty, "Like this post.");

在 Android 上,此属性的行为略有不同,具体取决于它所附加到的控件。 例如,对于没有文本值的控件,如 SwitchCheckBox,控件将显示提示和相应控件。 但是,对于具有文本值的控件,提示不会显示,并且是在文本值之后读取的。

警告

Hint 属性与 Android 上的 Entry.Placeholder 属性冲突,这两者都映射到同一平台属性。 因此,不建议将其他 Hint 值设置为 Entry.Placeholder 值。

标题级别

HeadingLevel 附加属性使一个元素可以被标记为标题,以组织 UI 并使其更易于导航。 某些屏幕阅读器使用户能够在标题之间快速跳转。

标题具有从 1 到 9 的级别,由 SemanticHeadingLevel 枚举表示,该枚举定义 None 并通过 Level9 成员定义 Level1

重要

虽然 Windows 提供 9 个级别的标题,但 Android 和 iOS 仅提供单个标题。 因此,在 Windows 上设置 HeadingLevel 时,它将映射到正确的标题级别。 但是,在 Android 和 iOS 上设置时,它将映射到单个标题级别。

下面的示例演示了如何设置此附加属性:

<Label Text="Get started with .NET MAUI"
       SemanticProperties.HeadingLevel="Level1" />
<Label Text="Paragraphs of text go here." />
<Label Text="Installation"
       SemanticProperties.HeadingLevel="Level2" />
<Label Text="Paragraphs of text go here." />    
<Label Text="Build your first app"
       SemanticProperties.HeadingLevel="Level3" />
<Label Text="Paragraphs of text go here." />     
<Label Text="Publish your app"
       SemanticProperties.HeadingLevel="Level4" />
<Label Text="Paragraphs of text go here." />   

也可在 C# 中进行设置:

Label label1 = new Label { Text = "Get started with .NET MAUI" };
Label label2 = new Label { Text = "Paragraphs of text go here." };
Label label3 = new Label { Text = "Installation" };
Label label4 = new Label { Text = "Paragraphs of text go here." };
Label label5 = new Label { Text = "Build your first app" };
Label label6 = new Label { Text = "Paragraphs of text go here." };
Label label7 = new Label { Text = "Publish your app" };
Label label8 = new Label { Text = "Paragraphs of text go here." };
SemanticProperties.SetHeadingLevel(label1, SemanticHeadingLevel.Level1);
SemanticProperties.SetHeadingLevel(label3, SemanticHeadingLevel.Level1);
SemanticProperties.SetHeadingLevel(label5, SemanticHeadingLevel.Level1);
SemanticProperties.SetHeadingLevel(label7, SemanticHeadingLevel.Level1);

此外,SetValue 方法也可用于设置 HeadingLevel 附加属性:

label1.SetValue(SemanticProperties.HeadingLevelProperty, SemanticHeadingLevel.Level1);

语义焦点

控件具有一个 SetSemanticFocus 扩展方法,该方法强制使屏幕阅读器焦点停留在指定的元素上。 例如,假设有一个名为 labelLabel,可强制使屏幕阅读器焦点停留在具有以下代码的元素上:

label.SetSemanticFocus();

语义屏幕阅读器

.NET MAUI 提供了 ISemanticScreenReader 接口,可以使用该接口指示屏幕阅读器为用户朗读文本。 该接口通过 Default 属性公开,并在 Microsoft.Maui.Accessibility 命名空间中可用。

若要指示屏幕阅读器朗读文本,需使用 Announce 方法,传递表示文本的 string 参数。 下面的示例演示了如何使用此方法:

SemanticScreenReader.Default.Announce("This is the announcement text.");

限制

必须启用默认平台屏幕阅读器才能大声朗读文本。

自动化属性

自动化属性是可添加到任何元素的附加属性,用于指示如何将元素报告给基础平台的辅助功能框架。

AutomationProperties 类定义以下附加属性:

  • 类型为 bool?ExcludedWithChildren 将确定是否应从辅助功能树中排除某元素及其子元素。 有关详细信息,请参阅 ExcludedWithChildren
  • IsInAccessibleTree,类型为 bool?,指示元素是否在辅助功能树中可用。 有关详细信息,请参阅 IsInAccessibleTree
  • Name,类型为 string,表示元素的简短描述,用作元素的朗读标识符。 有关详细信息,请参阅 Name
  • HelpText,类型为 string,元素的详细描述,可视作与元素关联的工具提示文本。 有关详细信息,请参阅 HelpText
  • LabeledBy,类型为 VisualElement,允许另一个元素定义当前元素的辅助功能信息。 有关详细信息,请参阅 LabeledBy

这些附加属性可设置平台辅助功能值,以便屏幕阅读器可以朗读元素。 有关附加属性的详细信息,请参阅附加属性

不同的屏幕阅读器会读取不同的辅助功能值。 因此,在使用自动化属性时,建议在每个平台上开展全面的辅助功能测试,从而确保获得最佳体验。

重要

自动化属性是在应用中提供辅助功能值的 Xamarin.Forms 方法,已经被语义属性取代。 有关语义属性的详细信息,请参阅语义属性

ExcludedWithChildren

ExcludedWithChildren 附加属性,类型为 bool?,确定是否应从辅助功能树中排除某个元素及其子元素。 这可实现诸如在其他布局(如 StackLayout)上显示 AbsoluteLayout 的方案,并且可从辅助功能树中排除 StackLayout(如果不可见)。 可以在 XAML 中使用它,具体如下:

<StackLayout AutomationProperties.ExcludedWithChildren="true">
...
</StackLayout>

或者,可在 C# 中设置如下:

StackLayout stackLayout = new StackLayout();
...
AutomationProperties.SetExcludedWithChildren(stackLayout, true);

设置此附加属性时,.NET MAUI 将 IsInAccessibleTree 附加属性设置为指定元素及其子元素上的 false

IsInAccessibleTree

警告

此附加属性通常应保持未设置状态。 大多数控件应存在于辅助功能树中,并且可以在需要从辅助功能树中删除某个元素及其子元素时,设置 AutomationProperties.ExcludedWithChildren 附加属性。

类型为 bool?IsInAccessibleTree 附加属性可确定元素是否对屏幕阅读器可见。 必须将其设置为 true 以使用其他自动化属性。 这可以通过以下操作在 XAML 中实现:

<Entry AutomationProperties.IsInAccessibleTree="true" />

或者,可在 C# 中设置如下:

Entry entry = new Entry();
AutomationProperties.SetIsInAccessibleTree(entry, true);

警告

在 iOS 上,如果在具有子级的任何控件上,IsInAccessibleTree 属性是 true,则屏幕阅读器无法到达子级。 这是因为 iOS 不提供允许从父元素导航到子元素的辅助功能。

名称

重要

Name 附加属性在 .NET 8 中已被弃用。 请改用 Description 属性。

Name 附加属性值应为屏幕阅读器用于公告元素的简短的描述性文本字符串。 应为具有对理解内容或与用户界面交互重要意义的元素设置此属性。 这可以通过以下操作在 XAML 中实现:

<ActivityIndicator AutomationProperties.IsInAccessibleTree="true"
                   AutomationProperties.Name="Progress indicator" />

或者,可在 C# 中设置如下:

ActivityIndicator activityIndicator = new ActivityIndicator();
AutomationProperties.SetIsInAccessibleTree(activityIndicator, true);
AutomationProperties.SetName(activityIndicator, "Progress indicator");

HelpText

重要

HelpText 附加属性在 .NET 8 中已被弃用。 请改用 Hint 属性。

HelpText 附加属性应设置为描述用户界面元素的文本,且可视为与元素关联的工具提示文本。 这可以通过以下操作在 XAML 中实现:

<Button Text="Toggle ActivityIndicator"
        AutomationProperties.IsInAccessibleTree="true"
        AutomationProperties.HelpText="Tap to toggle the activity indicator" />

或者,可在 C# 中设置如下:

Button button = new Button { Text = "Toggle ActivityIndicator" };
AutomationProperties.SetIsInAccessibleTree(button, true);
AutomationProperties.SetHelpText(button, "Tap to toggle the activity indicator");

在某些平台上,为了编辑控件例如 Entry,有时可以省略 HelpText 属性并将其替换为占位符文本。 例如,“在此输入名字”是 Entry.Placeholder 属性的一个很好的候选对象,它在用户实际输入之前将文本放在控件中。

LabeledBy

重要

LabeledBy 附件属性在 .NET 8 中已被弃用。 请改用 SemanticProperties.Description 绑定。 有关详细信息,请参阅 SemanticProperties:描述

LabeledBy 附加属性允许另一个元素定义当前元素的可访问性信息。 例如,Entry 旁的 Label 可用于描述 Entry 所表示的内容。 这可以通过以下操作在 XAML 中实现:

<Label x:Name="label" Text="Enter your name: " />
<Entry AutomationProperties.IsInAccessibleTree="true"
       AutomationProperties.LabeledBy="{x:Reference label}" />

或者,可在 C# 中设置如下:

Label label = new Label { Text = "Enter your name: " };
Entry entry = new Entry();
AutomationProperties.SetIsInAccessibleTree(entry, true);
AutomationProperties.SetLabeledBy(entry, label);

重要

iOS 不支持 AutomationProperties.LabeledByProperty

测试辅助功能

通常情况下,.NET MAUI 应用面向多个平台,这意味着需要根据具体平台测试辅助功能。 请按照以下链接,了解如何在每个平台上测试辅助功能:

以下工具可协助进行辅助功能测试:

但是,这些工具都无法完美模拟屏幕阅读器用户体验,而测试应用辅助功能并对其进行故障排除的最佳方法始终是在配备屏幕阅读器的物理设备上手动操作。

启用屏幕阅读器

每个平台都使用不同的默认屏幕阅读器来读出辅助功能值:

  • Android 具有 TalkBack。 有关启用 TalkBack 的信息,请参阅启用 TalkBack
  • iOS 和 macOS 具有 VoiceOver。 有关启用 VoiceOver 的信息,请参阅启用 VoiceOver
  • Windows 具有讲述人。 有关启用讲述人的信息,请参阅启用讲述人

启用 TalkBack

TalkBack 是 Android 上使用的主要屏幕阅读器。 启用方式取决于设备制造商、Android 版本和 TalkBack 版本。 但是,通常可以通过设备设置在 Android 设备上启用 TalkBack:

  1. 打开“设置”应用
  2. 选择“辅助功能”>“VoiceOver”
  3. 启用“使用 TalkBack”
  4. 选择“确定”

注意

虽然这些步骤适用于大多数设备,但可能会遇到一些差异。

首次启用 TalkBack 时,会自动打开 TalkBack 教程。

有关启用 TalkBack 的替代方法,请参阅请参阅打开或关闭 Talkback

启用 VoiceOver

VoiceOver 是 iOS 和 macOS 上使用的主要屏幕阅读器。 在 iOS 上,可以按如下所示启用 VoiceOver:

  1. 打开“设置”应用
  2. 选择“辅助功能”>“VoiceOver”
  3. 打开 VoiceOver

启用 VoiceOver 后,可以通过选择“VoiceOver 练习”打开 VoiceOver 教程。

有关启用 VoiceOver 的替代方法,请参阅在 iPhone 上打开并练习使用 VoiceOver在 iPad 上打开并练习使用 VoiceOver

在 macOS 上,可以按如下所示启用 VoiceOver:

  1. 打开“系统偏好设置”
  2. 选择“辅助功能”>“VoiceOver”
  3. 选择“启用 VoiceOver”
  4. 选择“使用 VoiceOver”

可以通过选择“打开 VoiceOver 培训...”来打开 VoiceOver 教程。

有关启用 VoiceOver 的替代方法,请参阅在 Mac 上打开或关闭 VoiceOver

启用讲述人

讲述人是 Windows 上使用的主要屏幕阅读器。 可以通过同时按 Windows 徽标键 + Ctrl + Enter 来启用讲述人。 可以再次按下这些键以停止讲述人。

有关讲述人的详细信息,请参阅讲述人完整指南

辅助功能清单

请按照以下提示操作,确保尽可能最广泛的受众可以轻松使用 .NET MAUI 应用:

  • 遵循 Web 内容辅助功能指南 (WCAG),确保应用可感知、可操作、可理解且可靠。 WCAG 是面向 Web 和移动端的全球性辅助功能标准和法律基准。 有关详细信息,请参阅 Web 内容辅助功能准则 (WCAG) 概述
  • 确保用户界面为自描述界面。 测试用户界面的所有元素是否都可访问屏幕阅读器。 根据需要添加描述性文本和提示。
  • 确保图像和图标包含备用文本说明。
  • 支持大字体和高对比度。 避免对控件尺寸进行硬编码,首选可调整大小以适应较大字号的布局。 在高对比度模式下测试配色方案,以确保其可读性。
  • 设计可视化树时需考虑导航功能。 使用适当的布局控件,以便使用备用输入法在控件之间导航时遵循与使用触控相同的逻辑流。 此外,从屏幕阅读器中排除不必要的元素(例如,已经可访问的字段的装饰图像或标签)。
  • 不要仅依赖音频或颜色提示。 避免仅使用声音或颜色的变化来指示进度、完成状态或其他状态的做法。 将用户界面设计为包含清晰的视觉提示,仅将声音和颜色用于强化,或者添加特定的辅助功能指示器。 选择颜色时,尽量避免使用色盲用户难以区分的调色板。
  • 为视频内容提供字幕,并为音频内容提供可读脚本。 提供用于调整音频或视频内容速度的控件,并确保音量和传输控件易于查找和使用,这样也很有帮助。
  • 当应用支持多种语言时,对辅助功能说明进行本地化。
  • 在应用所面向的每个平台上测试应用的辅助功能。 有关详细信息,请参阅测试辅助功能