2015-01-06 168 views
30

我试图确定发布UIAccessibilityLayoutChangedNotificationUIAccessibilityScreenChangedNotification时发生了什么不同。从我所看到的,我可以在任何地方交替使用它们,并且没有任何不同。UIAccessibilityLayoutChangedNotification和UIAccessibilityScreenChangedNotification之间的实际区别?

Apple文档简单地说如果(例如)一个元素被隐藏或显示时使用LayoutChanged,如果整个屏幕改变,则使用ScreenChanged,但是我对提供这些信息时他们做什么感兴趣,以及在使用其中一种时我会看到什么不同。

任何人都可以清楚地解释两者之间的实施差异吗?

回答

36

这两个通知针对视图上的动态内容,并将这些更改传递给屏幕阅读器用户的VoiceOver。这两个通知之间几乎没有什么区别,除了它们的默认行为,以及ScreenChange通知的傻小小“嘟嘟声”。

在这两种情况下,所述参数

UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, arg); 

表示一个字符串被读出,或屏幕元素,这将的VoiceOver其重点转向上。在发生剧烈的情境变化时,将焦点转移到有意义的地方或宣布发生了此类变化是很重要的。从可访问性的角度来看,任何一种方法都是可以接受的,尽管我更喜欢那些涉及最少可能变化的方法。在简单的布局改变的情况下,几乎总是最好的宣布上下文更改,并将焦点留在原来的位置。虽然有时候,导致上下文更改的元素是隐藏的,但是显然有必要指定配音来突出显示新内容,因为在这种情况下默认行为是未定义的,或者是确定性的,但是由一个完全不知道的框架决定关于你的应用!

这两个事件之间的区别,假设它们都做同样的事情,是在它们的默认行为。如果你提供零到UIAccessibilityLayoutChangedNotification就好像你没有做任何事情。如果您向UIAccessibilityScreenChangedNotification提供零参数,则会在所有视图层次更改和绘图完成后,将焦点发送到视图层次结构中标记为accessibilityElement的第一个UIObject。

UIAccessibilityLayoutChangedNotification

UIAccessibilityLayoutChangedNotification一个很好的使用情况实例是用于动态形式。您希望让用户知道,根据他们在表单中做出的决定,新选项可用。例如,如果在表单中选择自己是退伍军人,则可能会弹出表单的其他区域以提供更多输入,但这些区域可能已隐藏给其他不关心它们的用户。所以,你可以转移重心到用户交互之后这些元素:

UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, firstNewFormElement); 

这将焦点切换到提供的元素,并宣布它的accessibilityLabel。

或者只是告诉他们,新的表单元素有:

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

这会使注重它在哪里,但VoiceOver会会宣布“退伍军人组成可用元素”。

注意:此特定行为在我的iPad(8.1.2)上被窃听。

或者最后你可以这样做:

UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil); 

这也绝对没有什么:)。说真的,我甚至不认为这个框架后端关心。这一行代码是一个完整的浪费!

UIAccessibilityScreenChangedNotification

UIAccessibilityScreenChangedNotification一个很好的使用情况实例是定制的标签浏览的情况。当整个屏幕(除导航区域外)发生变化时。您希望让配音员知道基本上整个屏幕都发生了变化,但不会将第一个元素(您的第一个标签)聚焦,而是专注于第一个内容元素。

UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, firstNonGlobalNavElement); 

这将播放“嘟嘟声”的声音,然后将焦点转移到您的全局导航栏下方。或者你可以这样做:

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

这将等待新的标签,加载,发挥“嘟BOOP”的声音,宣布“你是一个新的选项卡上的”画外音中,然后将焦点切换到第一元素,然后宣布该元素的accessibilityLabel。 (PHEW!这太多了!这对于屏幕阅读器用户来说是很刺激的。避免这种情况,除非绝对必要)。

最后,你当然可以这样做:

UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);  

即相当于:

UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, firstA11yElement); 

这两者将发挥“嘟BOOP”的声音,VoiceOver的重点转移到第一元素在屏幕上,然后宣布它。

最后

在评论中提到有人缓存,并且我偶尔在我对事物的A11Y后端可能会或可能不会在意答案评论。尽管发生后端魔术当然有可能发生,但我不相信这两种情况之一,后端根本就不在乎。我之所以这么说是因为:

如果你曾经使用过UIAccessibilityContainer协议,你可以看你的视图容器被查询。没有缓存正在进行。每次VoiceOver将焦点更改为容器中新的AccessibilityElement时,即使accessibilityElementCount属性也会被触发。然后它检查它所在的元素,询问下一个元素,等等。它的核心是处理动态情况。如果在交互之后要将新元素插入到容器中,它仍然会经历所有这些查询,并对其进行处理!此外,如果您重写UIAccessibility协议的属性,为了提供动态提示和标签,您还可以看到每次都会调用这些函数!因此,我相信A11y Framework后端从这些通知中搜集绝对零度的信息。 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

最后,愚蠢的小应用程序,我放在一起测试所有这些东西的一个开源回购。

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

+3

钉住它。对'UIAccessibilityContainer'进行测试的好主意。 – Justin

+3

完美。谢谢。我同意@Justin。我还转载了你提到的并提交了雷达的错误。 –

+2

很好的答案。关于缓存的部分,我只有轻微的不同意见。我100%肯定某处有某种缓存。说明:我对'UIAccessibilityContainer'做了一些测试,就像你说的那样,容器方法在焦点移动时被调用。但是,无论容器协议方法返回什么,在某些情况下,如果您没有明确发布布局/屏幕更改通知,则配音会一直读取错误的值。所以有引擎盖下的缓存。它可能不会单独缓存元素,但它会缓存(元素,位置)对或这些行周围的内容。 –

-1

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

UIAccessibilityLayoutChangedNotification用于指示屏幕上的一个或多个但不是全部元素已经改变。

当您的用户界面发生巨大变化时。通常当用户移动到应用程序的不同部分(导航到不同的屏幕)时。 VoiceOver通过声音通知用户,并清除其缓存,并进行其他准备工作来处理一组新的辅助功能数据。它会向VoiceOver发出警报,表明屏幕已更改,并且屏幕上可能有新元素,因此VoiceOver将重新构建其无障碍元素索引。

UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil); 

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

UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil); 
+3

这些都是公平的例子,但他们没有回答这个问题。您是否可以提供证据来支持以下声明:A)VoiceOver响应屏幕更改通知而“清除其缓存”,但不响应布局更改通知; B)Voiceover“响应屏幕更改通知用户声音”但不是布局更改? – Justin

相关问题