在发布UIAccessibilityLayoutChangedNotification
和UIAccessibilityScreenChangedNotification
时,我正在尝试确定不同的确切方法。从我所看到的,我可以在任何地方互换使用它们,没有任何不同的事情发生。
Apple文档只是说(例如)一个元素被隐藏或显示时使用LayoutChanged
,如果整个屏幕发生变化则使用ScreenChanged
,但我对他们感兴趣当我提供这些信息时,以及在使用其中一种时我应该看到的不同。
任何人都可以清楚地解释两者之间的实施差异吗?
答案 0 :(得分:50)
这两个通知用于视图上的动态内容,并将这些更改传达给屏幕阅读器用户的VoiceOver。这两个通知之间几乎没有什么区别,除了它们的默认行为,以及愚蠢的小小的" boop beep"用于ScreenChange通知。
在两个实例中,参数
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, arg);
表示要读出的字符串或屏幕元素,VoiceOver会将其焦点移至。如果发生剧烈的背景变化,重点是将焦点发送到有意义的地方,或者宣布已经发生了这样的变化。从可访问性的角度来看,这两种方法都是可以接受的,尽管我更喜欢可能涉及最少量更改的方法。在简单的布局更改的情况下,几乎总是最好只宣布上下文更改,并将焦点保留在原来的位置。虽然有时会导致上下文更改的元素被隐藏,但显然有必要指示画外音来突出显示新内容,因为在这种情况下默认行为是未定义的,或者可能是确定性的,但是由一个完全不知道的框架决定关于你的应用程序!
两个事件的区别在于它们都完全相同,它们的默认行为。如果你向UIAccessibilityLayoutChangedNotification
提供nil就好像你什么也没做。如果为UIAccessibilityScreenChangedNotification
提供nil参数,它将把焦点发送到视图层次结构中标记为accessibilityElement的第一个UIObject,一旦所有视图层次结构发生变化并且绘图完成。
<强> UIAccessibilityLayoutChangedNotification 强>
UIAccessibilityLayoutChangedNotification
的一个很好的用例示例是动态表单。您希望让用户知道,根据他们在表单中做出的决定,可以使用新选项。例如,如果在表单中选择您是退伍军人,则可能会弹出表单的其他区域以提供更多输入,但这些区域可能已隐藏给其他不关心它们的用户。因此,您可以在用户交互后将焦点转移到这些元素:
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, firstNewFormElement);
将焦点转移到提供的元素,并宣布它的accessibilityLabel。
或者告诉他们新的表单元素在那里:
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, @"Veterans form elements available");
哪会留下焦点,但VoiceOver会宣布&#34;退伍军人形成可用的元素&#34;。
注意:我的iPad(8.1.2)上会出现这种特殊行为。
或者最后你可以这样做:
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
哪个绝对没有:)。说真的,我甚至不认为a11y框架后端关心。这段特殊的代码完全是浪费!
<强> UIAccessibilityScreenChangedNotification 强>
UIAccessibilityScreenChangedNotification
的一个很好的用例示例是自定义标签式浏览情境。当整个屏幕(导航区域除外)发生变化时。您想让画外音知道基本上整个屏幕都已更改,但不要聚焦第一个元素(第一个选项卡),而是聚焦第一个内容元素。
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, firstNonGlobalNavElement);
哪个会播放&#34; boop beep&#34;声音,然后将焦点转移到全局导航栏下方。或者你可以这样做:
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, @"You're on a new tab");
哪个会等待新标签加载,播放&#34; beep boop&#34;声音,宣布&#34;你正在新标签上#34;在画外音中,然后将焦点移到屏幕上的第一个元素,然后宣布该元素的accessibilityLabel。 (PHEW!那太多了!这对于屏幕阅读器用户来说是不和谐的。除非绝对必要,否则请避免这种情况。)
最后你当然可以这样做:
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
相当于:
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, firstA11yElement);
这两个都将播放&#34; beep boop&#34;声音,移动VoiceOver焦点到屏幕上的第一个元素,然后宣布它。
<强>最后强>
在评论中有人提到了缓存,我偶尔会在答案中评论A11y后端可能会或可能不会关心的事情。虽然有可能发生一些后端魔法,但我不相信这两种情况,后端都在乎。我说这个的原因是因为:
如果您曾使用UIAccessibilityContainer
协议,则可以在查看您的容器视图时进行监视。没有缓存正在进行中。每当VoiceOver将焦点更改为容器中的新AccessibilityElement时,即使accessibilityElementCount
属性也会被ping。然后它会检查它所在的元素,询问下一个元素,等等。它的核心是处理动态情况。如果你在交互后将一个新元素插入到容器中,它仍然会经历所有这些查询并且对它很好!此外,如果您覆盖UIAccessibility协议的属性,为了提供动态提示和标签,您还可以看到每次调用这些函数!因此,我相信A11y框架后端从这些通知中收集了绝对零的信息。 VoiceOver需要完成其工作的唯一信息是它当前关注的辅助功能元素,以及此元素辅助功能容器。这些通知只是为了让您的应用对VoiceOver用户更有用。
想象一下,如果这不是Safari会发布这些通知多少次!!!! :)
这些特定的陈述只能由具有框架后端知识,使用代码的人确认,并且应该被视为猜想。情况可能是这是高度版本/实现依赖的。绝对愿意讨论这些问题!这篇文章的其余部分非常具体。
供您参考
大部分内容来自使用框架的经验,但如果您想进一步挖掘,这里有一个有用的参考。
https://developer.apple.com/documentation/uikit/accessibility/uiaccessibility
https://developer.apple.com/documentation/uikit/uiaccessibilitylayoutchangednotification
https://developer.apple.com/documentation/uikit/uiaccessibilityscreenchangednotification
最后,我把一个愚蠢的小应用程序的开源回购集合在一起测试所有这些东西。
答案 1 :(得分:-1)
UIAccessibilityScreenChangedNotification
表示整个屏幕已更改,VoiceOver应重置。
UIAccessibilityLayoutChangedNotification
表示屏幕上的一个或多个(但不是全部)元素已更改。
当您的UI发生显着变化时通常当用户移动到应用程序的不同部分时(导航到不同的屏幕)。 VoiceOver会以语音通知用户,并清除其缓存并进行其他准备工作以处理一组新的辅助功能数据。它警告VoiceOver屏幕已更改,屏幕上可能有新元素,因此VoiceOver将重建它的可访问性元素索引。
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
如果您的UI的某些部分发生了变化,但用户未必跳到应用程序的完全不同的部分。 (例如:在iTunes Store应用程序中,点击歌曲旁边的价格标签(0.99美元等)会将其更改为“购买”按钮。)此通知告知VoiceOver重新读取所有可访问项目的当前状态在屏幕上,通过这样做,它可以找出变化的内容并通知用户这些变化。它警告VoiceOver布局已更改,并且当前索引已过期,因为屏幕上的项目已自行重新排序。
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);