UIAccessibilityLayoutChangedNotification 和 UIAccessibilityScreenChangedNotification 之间的实际区别?

Actual difference between UIAccessibilityLayoutChangedNotification and UIAccessibilityScreenChangedNotification?

我正在尝试确定在发布 UIAccessibilityLayoutChangedNotificationUIAccessibilityScreenChangedNotification 时到底发生了什么不同。据我所知,我可以在任何地方互换使用它们,没有任何不同。

Apple 文档只是说当(例如)某个元素被隐藏或显示时使用 LayoutChanged,如果整个屏幕发生变化则使用 ScreenChanged,但我感兴趣的是当我提供这些信息时他们做了什么,以及在使用其中一个或另一个时我应该看到什么不同。

有谁能清楚的解释一下两者在实现上的区别吗?

UIAccessibilityScreenChangedNotification表示整个屏幕已经改变,VoiceOver应该重置。

UIAccessibilityLayoutChangedNotification是表示屏幕上的一个或多个元素发生了变化,但不是全部。

当您的 UI 发生巨大变化时。通常当用户移动到应用程序的不同部分时(导航到不同的屏幕)。 VoiceOver 会通过提示音通知用户,并清除其缓存并做其他准备工作以处理一组新的辅助功能数据。它提醒 VoiceOver 屏幕已更改并且屏幕上可能有新元素,因此 VoiceOver 将重建它的辅助功能元素索引。

UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);

如果您的 UI 的某些部分发生了变化,但用户不一定跳转到您应用的完全不同的部分。 (例如:在 iTunes Store 应用程序中,点击歌曲旁边的价格标签($0.99 等)会将其更改为“购买”按钮。)此通知告诉 VoiceOver 重新读取所有可访问项目的当前状态在屏幕上,通过这样做,它可以找出发生了什么变化并将这些变化通知用户。它会提醒 VoiceOver 布局已更改并且它的当前索引已过时,因为屏幕上的项目已自行重新排序。

UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);

这两个通知针对视图上的动态内容,并将这些更改传达给屏幕reader 用户的 VoiceOver。除了它们的默认行为和用于 ScreenChange 通知的愚蠢的小 "boop beep" 之外,这两个通知之间几乎没有区别。

在这两种情况下,参数

UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, arg);

表示要读出的字符串或屏幕上的元素,VoiceOver 会将其焦点转移到该元素。如果发生戏剧性的环境变化,重要的是将焦点转移到有意义的地方,或者宣布发生了此类变化。从可访问性的角度来看,这两种方法都是可以接受的,但我更喜欢涉及尽可能少的更改的方法。如果发生简单的布局更改,几乎总是最好只是宣布上下文更改,并将焦点留在原处。虽然有时候,导致上下文变化的元素是隐藏的,然后显然有必要直接画外音来突出显示新内容,因为这种情况下的默认行为是未定义的,或者可能是确定性的,但由一个一无所知的框架决定关于您的应用!

这两个事件之间的区别在于它们的默认行为,因为它们都做完全相同的事情。如果您向 UIAccessibilityLayoutChangedNotification 提供 nil,就好像您什么也没做。如果您向 UIAccessibilityScreenChangedNotification 提供一个 nil 参数,一旦所有视图层次结构发生变化并且绘制完成,它会将焦点发送到视图层次结构中标记为 accessibilityElement 的第一个 UIObject。

UIAccessibilityLayoutChangedNotification

UIAccessibilityLayoutChangedNotification 的一个很好的用例示例是动态表单。您想让用户知道,根据他们在表单中所做的决定,可以使用新选项。例如,如果在表单中您 select 表明您是退伍军人,则可能会弹出表单的其他区域以提供更多输入,但这些区域可能对不关心它们的其他用户隐藏。因此,您可以在用户交互后将焦点转移到这些元素:

UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, firstNewFormElement);

这会将焦点转移到提供的元素,并宣布它是 accessibilityLabel。

或者直接告诉他们有新的表单元素:

UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, @"Veterans form elements available");

这会将焦点留在原处,但 VoiceOver 会宣布 "Veterans form elements available"。

注意:此特定行为在我的 iPad (8.1.2) 上存在错误。

或者最后你可以这样做:

UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);

什么都不做 :)。说真的,我什至不认为 a11y 框架后端关心。这行代码完全是浪费!

UIAccessibilityScreenChangedNotification

UIAccessibilityScreenChangedNotification 的一个很好的用例示例是自定义选项卡式浏览情况。当整个屏幕(导航区域除外)发生变化时。您想让画外音知道整个屏幕基本上都发生了变化,但不是聚焦第一个元素(您的第一个选项卡)而是聚焦第一个内容元素。

UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, firstNonGlobalNavElement);

这将播放 "boop beep" 声音,然后将焦点转移到全局导航栏正下方。或者你可以这样做:

UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, @"You're on a new tab");

等待新标签加载,播放 "beep boop" 声音,在画外音中宣布 "You're on a new tab",然后将焦点转移到屏幕上的第一个元素,然后宣布该元素的 accessibilityLabel元素。 (PHEW!太多了!这对屏幕 reader 用户来说很刺耳。除非绝对必要,否则请避免这种情况)。

最后你当然可以这样做:

UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);    

相当于:

UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, firstA11yElement);

两者都会播放 "beep boop" 声音,将 VoiceOver 焦点转移到屏幕上的第一个元素,然后宣布它。

终于

在评论中有人提到了缓存,我偶尔会在我的回答中评论 A11y 后端可能关心或不关心的事情。虽然肯定有可能发生一些后端魔术,但我不相信这两种情况,后端根本不关心。我之所以这样说是因为:

如果您曾经使用过 UIAccessibilityContainer 协议,您可以看到您的视图容器被查询。没有缓存进行。每次 VoiceOver 将焦点更改到容器中的新 AccessibilityElement 时,甚至 accessibilityElementCount 属性 也会收到 ping 通知。然后它会检查它在哪个元素上,询问下一个元素,等等。它的核心设计是处理动态情况。如果您要在交互后将一个新元素插入到您的容器中,它仍然会通过所有这些查询并且会很好!此外,如果您覆盖 UIAccessibility 协议的属性,以提供动态提示和标签,您还可以看到每次都会调用这些函数!因此,我相信 A11y 框架后端从这些通知中收集的信息绝对为零。 VoiceOver 完成其工作所需的唯一信息是它当前关注的辅助功能元素,以及该元素的辅助功能容器。通知只是为了让您的应用程序对 VoiceOver 用户更有用。

想象一下,如果不是这种情况,Safari 会 post 这些通知多少次!!!! :)

这些特定的陈述只能由具有框架后端知识、使用代码的人确认,应被视为推测。这可能是高度 version/implementation 依赖的情况。绝对可以就这些要点进行讨论! post 的其余部分非常具体。

供您参考

其中大部分来自使用框架的经验,但如果您想进一步挖掘,这里是一个有用的参考。

https://developer.apple.com/documentation/uikit/accessibility/uiaccessibility

https://developer.apple.com/documentation/uikit/uiaccessibilitylayoutchangednotification

https://developer.apple.com/documentation/uikit/uiaccessibilityscreenchangednotification

最后,这是我用来测试所有这些东西的愚蠢小应用程序的开源存储库。

https://github.com/chriscm2006/IOS-A11y-Api-Test