UIAccessibilityLayoutChangedNotification和UIAccessibilityScreenChangedNotification之间的实际差异?

Luk*_*uke 35 accessibility ios uiaccessibility

我试图确定在发布a UIAccessibilityLayoutChangedNotification和a 时确切地发生了什么UIAccessibilityScreenChangedNotification.从我所看到的,我可以在任何地方互换使用它们,没有任何不同的事情发生.

Apple文档只是说LayoutChanged当(例如)一个元素被隐藏或显示时使用,并ScreenChanged在整个屏幕发生变化时使用,但我对他们提供这些信息时所做的事情感兴趣,以及我应该看到的不同之处当使用其中一个时.

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

Chr*_*sCM 50

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

在这两个例子中,论证

UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, arg);
Run Code Online (Sandbox Code Playgroud)

表示要读出的字符串或屏幕元素,VoiceOver将其焦点移至.如果发生剧烈的背景变化,重点是将焦点发送到有意义的地方,或者宣布已经发生了这样的变化.从可访问性的角度来看,这两种方法都是可以接受的,尽管我更喜欢可能涉及最少量更改的方法.在简单的布局更改的情况下,几乎总是最好只宣布上下文更改,并将焦点保留在原来的位置.虽然有时会导致上下文更改的元素被隐藏,然后显然需要指示画外音来突出显示新内容,因为在这种情况下默认行为是未定义的,或者可能是确定性的,但是由一个完全不知道的框架决定关于你的应用!

两个事件之间的区别,因为它们都完全相同,它们的默认行为.如果你提供零,UIAccessibilityLayoutChangedNotification就好像你什么也没做.如果为其提供nil参数,UIAccessibilityScreenChangedNotification则会在所有视图层次结构更改且绘图完成后将焦点发送到视图层次结构中标记为accessibilityElement的第一个UIObject.

UIAccessibilityLayoutChangedNotification

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

UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, firstNewFormElement);
Run Code Online (Sandbox Code Playgroud)

这将把焦点转移到提供的元素,并宣布它的accessibilityLabel.

或者只是告诉他们新的表单元素在那里:

UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, @"Veterans form elements available");
Run Code Online (Sandbox Code Playgroud)

哪会留下焦点,但VoiceOver会宣布"退伍军人形式元素可用".

注意:我的iPad(8.1.2)上会出现此特定行为.

或者最后你可以这样做:

UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
Run Code Online (Sandbox Code Playgroud)

哪个绝对没有:).说真的,我甚至不认为a11y框架后端关心.这段特殊代码完全是浪费!

UIAccessibilityScreenChangedNotification

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

UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, firstNonGlobalNavElement);
Run Code Online (Sandbox Code Playgroud)

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

UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, @"You're on a new tab");
Run Code Online (Sandbox Code Playgroud)

等待新标签加载,播放"beep boop"声音,在画外音中宣布"你在新标签上",然后将焦点转移到屏幕上的第一个元素,然后宣布该元素的accessibilityLabel.(PHEW!这很多!这对于屏幕阅读器用户来说是不和谐的.除非绝对必要,否则避免这种情况).

最后你当然可以这样做:

UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);    
Run Code Online (Sandbox Code Playgroud)

这相当于:

UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, firstA11yElement);
Run Code Online (Sandbox Code Playgroud)

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

最后

在评论中,有人提到缓存,我偶尔会在答案中评论A11y后端可能会或可能不会关心的事情.虽然有可能发生一些后端魔法,但我不相信这两种情况,后端都在乎.我说这个的原因是因为:

如果您曾经使用过UIAccessibilityContainer协议,则可以在查看容器视图时进行监视.没有缓存正在进行中.accessibilityElementCount每当VoiceOver将焦点更改为容器内的新AccessibilityElement时,甚至该属性也会被ping.然后它会检查它所在的元素,询问下一个元素,等等.它的核心是处理动态情况.如果你在交互后将一个新元素插入到容器中,它仍然会经历所有这些查询并且对它很好!此外,如果您覆盖UIAccessibility协议的属性,为了提供动态提示和标签,您还可以看到每次调用这些函数!因此,我相信A11y框架后端从这些通知中收集了绝对零的信息.VoiceOver需要完成其工作的唯一信息是它目前专注于Accessibility Element,并且这个元素是Accessibility Container.这些通知只是为了让您的应用对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

  • 搞定了.测试`UIAccessibilityContainer`的好主意. (3认同)
  • 完善.谢谢.我同意@Justin.我还复制了你提到的错误并提交了雷达. (3认同)
  • 很好的答案.关于缓存,我只是略微不同意.我100%肯定某处有某种缓存.说明:我对`UIAccessibilityContainer`进行了一些测试,就像你说的那样,当焦点移动时会调用容器方法.但是,无论容器协议方法返回什么,在某些情况下,如果您没有明确发布布局/屏幕更改通知,配音将继续读取错误的值.因此,引擎盖下有缓存.它可能不会单独缓存元素,但它会缓存(元素,位置)对或这些行周围的东西. (2认同)