UIAccessibilityLayoutChangedNotification和UIAccessibilityScreenChangedNotification之间的实际区别?

我试图确定究竟发生了什么事发布UIAccessibilityLayoutChangedNotificationUIAccessibilityScreenChangedNotification 。 从我所能看到的,我可以在任何地方交替使用它们,没有什么不同。

苹果文档简单地说,当(例如)一个元素被隐藏或显示时使用ScreenChanged如果整个屏幕变化,则使用ScreenChanged ,但是当我提供这些信息时,我感兴趣的是他们做了什么,当使用其中一个或另一个时,看到不同。

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

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

在这两个例子中,论点

 UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, arg); 

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

这两个事件之间的差异,因为他们都做同样的事情,是在他们的默认行为。 如果您向UIAccessibilityLayoutChangedNotification提供nil,就好像您没有做任何事情。 如果向UIAccessibilityScreenChangedNotification提供一个零参数,那么一旦所有视图层次结构更改和绘图完成,它将把焦点发送到视图层次结构中标记为accessibilityElement的第一个UIObject。

UIAccessibilityLayoutChangedNotification

UIAccessibilityLayoutChangedNotification一个很好的用例是dynamic表单。 您希望让用户知道,根据他们在表单中做出的决定,新的选项可用。 例如,如果在表单中select自己是退伍军人,则可能会popup表单的其他区域以提供更多input,但这些区域可能已经隐藏给其他不关心它们的用户。 所以你可以在用户交互之后将焦点转移到这些元素上:

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

这将等待新标签加载,播放“哔哔哔哔”声,在配音中宣布“您正在新标签上”,然后将焦点移至屏幕上的第一个元素,然后宣布该元素的accessibilityLabel。 (PHEW!这太多了!这对于屏幕阅读器用户来说是震惊的,除非绝对必要,否则请避免这种情况)。

最后你可以这样做:

 UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil); 

这相当于:

 UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, firstA11yElement); 

两者都会播放“哔哔哔哔”声,将VoiceOver对焦移到屏幕上的第一个元素,然后通知它。

最后

在有人提到caching的评论中,我偶尔会在我的回答中评论A11y后端可能会或可能不会在意的事情。 虽然有一些后端魔术当然有可能发生,但我不相信这两种情况之一,后端关心。 我这样说的原因是因为:

如果你曾经使用UIAccessibilityContainer协议,你可以看你的视图容器被查询。 没有caching正在进行。 每当VoiceOver将焦点更改为容器中新的AccessibilityElement时,即使accessibilityElementCount属性也会被触发。 然后,它会经过检查它在哪个元素上的过程,请求下一个元素,等等。 它的核心是处理dynamic情况。 如果您在交互之后将新元素插入到容器中,它仍然会经历所有这些查询,并且可以很好地处理它! 而且,如果你重写UIAccessibility协议的属性,为了提供dynamic的提示和标签,你也可以看到这些函数每次都被调用! 因此,我相信A11y Framework后端从这些通知中搜集绝对零度的信息。 VoiceOver需要完成的唯一信息就是当前关注的辅助function元素,以及此元素的辅助function容器。 通知只是为了让您的应用程序更适合VoiceOver用户使用。

想象一下,如果这不是Safari多less次发布这些通知!!!! 🙂

这些特定的陈述只能由具有该框架的后端知识的人员来确认,他们使用该代码,并且应该被视为猜想。 这可能是高度版本/实现相关的情况。 肯定会对这些问题进行讨论! 这篇文章的其余部分非常具体。

供你参考

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

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

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

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

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

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

UIAccessibilityScreenChangedNotification指示整个屏幕已更改,VoiceOver应重置。

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

当你的用户界面变化很大。 通常当用户移动到您的应用程序的不同部分(导航到不同的屏幕)。 VoiceOver通过声音通知用户,并清除其caching,并做其他准备处理一组新的可访问性数据。 它提醒VoiceOver屏幕已经改变,并且屏幕上可能有新的元素,所以VoiceOver将重build它的可访问性元素的索引。

 UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil); 

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

 UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);