使用语义属性生成可访问的应用

辅助功能语义主要用于生成各种体验,使你的应用对用户具有包容性,方便其在各种环境中使用技术并满足其对 UI 的一系列需求和体验要求。 在许多情况下,辅助功能的法律要求可能会为开发人员解决辅助功能问题提供动力。 不管怎样,建议构建包容性和可访问性应用,使应用达到可能的最大受众。

Web 内容辅助功能准则(WCAG)是 Web 和移动的全球辅助功能标准和法律基准。 这些准则描述了使应用更加可感知、可操作、可理解和可靠的各种方法。

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

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

作系统有自己的屏幕阅读器,具有自己的独特行为和配置。 例如,大多数屏幕阅读器在收到焦点时读取与控件关联的文本,使用户在浏览应用时能够自行定位。 但是,某些屏幕阅读器还可以在页面出现时读取整个应用用户界面,这样用户就可以在尝试导航页面之前接收所有页面的可用信息性内容。

大多数屏幕阅读器会自动阅读与接收辅助功能焦点的控件关联的任何文本。 这意味着具有Label属性集的控件,例如Button或Text,用户将可以访问。 但是,由于Image、ImageButton、ActivityIndicator和其他元素没有与辅助功能树关联的文本,因此它们可能不在辅助功能树中。

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

注释

当WebView显示可访问的网站时,它在 .NET MAUI 应用中也将是可访问的。 相反,WebView 如果显示的是一个无法访问的网站,那么在 .NET MAUI 应用中也将无法访问。

语义属性

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

重要

语义属性不会尝试在每个平台上强制执行等效行为。 相反,它们依赖于每个平台提供的可访问性使用体验。

该 SemanticProperties 类定义以下附加属性:

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

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

DESCRIPTION

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!");

也可以在另一个元素上定义某元素的辅助功能信息。 例如, Label 旁边的 Switch 可以用来描述 Switch 的含义。 这可以在 XAML 中完成,如下所示:

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

或者,可以在 C# 中设置它,如下所示:

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

警告

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

提示

Hint附加属性代表一个string,它为Description附加属性提供附加的上下文,例如控件的用途。 可以在 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 上,此属性的行为略有不同,具体取决于它附加到的控件。 例如,对于没有文本值的控件,例如Switch和CheckBox,这些控件将显示提示。 但是,对于具有文本值的控件,提示不会显示,并且是在文本值之后读取的。

警告

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

标题级别

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

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

重要

虽然 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.Level2);
SemanticProperties.SetHeadingLevel(label5, SemanticHeadingLevel.Level3);
SemanticProperties.SetHeadingLevel(label7, SemanticHeadingLevel.Level4);

此外, 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 类定义以下附加属性:

  • ExcludedWithChildren 的 bool? 类型,决定某个元素及其子元素是否应被排除在无障碍树之外。 有关详细信息,请参阅 ExcludedWithChildren。
  • IsInAccessibleTree的类型bool?指示该元素是否在辅助功能树中可用。 有关详细信息,请参阅 IsInAccessibleTree。
  • Name,类型为 string,表示元素的简短描述,用作元素的朗读标识符。 有关详细信息,请参阅名称。
  • HelpText类型 string,表示元素的较长说明,可以将其视为与元素关联的工具提示文本。 有关详细信息,请参阅 HelpText。
  • LabeledBy,类型 VisualElement,使另一个元素能够定义当前元素的可访问性信息。 有关详细信息,请参阅 LabeledBy。

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

不同的屏幕阅读器读取不同的无障碍功能值。 因此,使用自动化属性时,建议在每个平台上执行彻底的辅助功能测试,以确保获得最佳体验。

重要

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

ExcludedWithChildren

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

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

或者,可以在 C# 中设置它,如下所示:

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

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

IsInAccessibleTree

警告

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

类型为 IsInAccessibleTree 的 bool? 附加属性可确定元素是否对屏幕阅读器可见。 必须将其设置为true才能使用其他自动化属性。 这可以在 XAML 中完成,如下所示:

<Entry AutomationProperties.IsInAccessibleTree="true" />

或者,可以在 C# 中设置它,如下所示:

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

警告

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

.NET 11 中的 Windows 布局的 UI 自动化行为

从 .NET MAUI 11 开始,Windows 对 Layout 和 ContentView 容器使用 MauiLayoutAutomationPeer。 默认情况下,这种 Windows 特有的行为会将匿名布局容器排除在 UI 自动化(UIA)视图之外,同时保留用于 UI 测试的 AutomationId 发现能力。

在 Layout 或 ContentView 上的 Windows 设置 UIA 原始视图 UIA 控件视图 UIA 内容视图
无自动化或语义可访问性信号 排除 排除 排除
仅 AutomationId Included 作为 Custom 包含,没有本地化控件类型 排除
IsInAccessibleTree 是 true Included Included Included
Description 或 Hint 已设置 Included Included 排除
将 IsInAccessibleTree 设置为 false 以显式退出 仅包含在 UIA 原始视图中 已排除,即使同时设置了 AutomationId、Description 或 Hint 也是如此 排除

当布局或 ContentView 仅需要 Windows UI 测试挂钩时,使用 AutomationId。 仅当需要由屏幕阅读器(例如“讲述人”或 NVDA)读出容器本身时,才使用 Description、Hint 或将 IsInAccessibleTree 设置为 true。 若要将容器排除在无障碍树之外,请将 IsInAccessibleTree 设置为 false;这种显式退出的优先级高于 AutomationId 和语义无障碍值。

名称

重要

在 .NET 8 中,Name 附加属性已被弃用。 请改用 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

重要

在 .NET 8 中,HelpText 附加属性已被弃用。 请改用 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

重要

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

LabeledBy 附加属性使另一个元素能够定义当前元素的辅助功能信息。 例如, Label 旁边的 Entry 可以用来描述 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. 选择 Accessibility>TalkBack。
  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)概述。
  • 确保用户界面为自描述界面。 测试用户界面的所有元素是否对屏幕阅读器可访问。 根据需要添加描述性文本和提示。
  • 确保图像和图标具有备用文本说明。
  • 支持大字体和高对比度。 避免对控件尺寸进行硬编码,首选可调整大小以适应较大字号的布局。 在高对比度模式下测试配色方案,以确保它们可读。
  • 在设计可视化树时要考虑导航。 请使用合适的布局控件,这样在控件之间使用其他输入方法进行导航时,可以遵循与触摸输入相同的逻辑流程。 此外,从屏幕阅读器中排除不必要的元素(例如,已可访问的字段的装饰图像或标签)。
  • 不要单独依赖音频或颜色提示。 避免出现进度、完成或其他状态的唯一指示是声音或颜色更改的情况。 要么设计用户界面以包含清晰的视觉提示,并仅将声音和颜色用于强化,要么添加特定的辅助功能指示器。 选择颜色时,请尽量避免使用色盲用户难以区分的调色板。
  • 提供视频内容的字幕和音频内容的可读脚本。 它还有助于提供调整音频或视频内容速度的控件,并确保音量和传输控件易于查找和使用。
  • 当应用支持多种语言时,本地化辅助功能说明。
  • 在应用所面向的每个平台上测试应用的辅助功能。 有关详细信息,请参阅测试辅助功能。