聚焦非 UILabel titleView 时,VoiceOver 读取辅助功能标签两次 [英] VoiceOver reads accessibility label twice when focusing non-UILabel titleView
问题描述
我在使用 VoiceOver 时遇到了一个奇怪的问题.
I'm encountering a strange issue with VoiceOver.
目标:
- 设置一个包含多个
UILabel
的UIStackView
作为我的navigationItem.titleView
. - 将堆栈视图标记为可访问性元素,并将其
accessibilityLabel
设置为适当的值. - 通过在
viewDidAppear(animated:)
中调用UIAccessibility.post(notification: .screenChanged, argument: navigationItem.titleView)
将堆栈视图设置为初始 VoiceOver 焦点.
- Set a
UIStackView
containing multipleUILabel
's as mynavigationItem.titleView
. - Mark the stack view as an accessibility element and set its
accessibilityLabel
to an appropriate value. - Set the stack view as the initial VoiceOver focus by calling
UIAccessibility.post(notification: .screenChanged, argument: navigationItem.titleView)
insideviewDidAppear(animated:)
.
预期结果:
- 当视图控制器出现时,焦点似乎在标题视图上,VoiceOver 会读取无障碍标签的内容一次.
实际结果:
- VoiceOver 开始读取可访问性标签的内容,然后在中途(或有时在完成后)继续读取第二次.
如果我将 navigationItem.titleView
设置为 UILabel
的实例,则不会出现此问题.
This issue does not occur if I set navigationItem.titleView
to an instance of UILabel
.
有谁知道为什么会这样?这是 iOS 中的错误吗?
Does anyone know why this happens? Is it a bug in iOS?
我在这里建立了一个简单的项目来演示这个问题:https://github.com/rzulkoski/Focus-TitleView-Bug
I have set up a simple project demonstrating the issue here: https://github.com/rzulkoski/Focus-TitleView-Bug
推荐答案
第二次阅读标题的原因在于您的代码.
The reason why you have a second time reading of your title is in your code.
在您的 viewDidLoad
中,您设置了 VoiceOver 自动读出的堆栈视图可访问性标签,以通知用户更改.
In your viewDidLoad
, you set the stackview accessibility label that VoiceOver automatically reads out to inform the user of the changing.
接下来,您通过 viewDidAppear
中的帖子通知此更改,VoiceOver 自然也会读出.
Next, you notify this changing with a post in your viewDidAppear
that VoiceOver naturally reads out as well.
要防止这种行为,只需删除 setupNavigationItem
函数中的 stackView.accessibilityLabel = label.text
并将此代码段添加到您的私有惰性 var 标签 init 中:>
To prevent from this behavior, just delete stackView.accessibilityLabel = label.text
in your setupNavigationItem
function and add this snippet in your private lazy var label init :
if (self.view.subviews.contains(stackView)) {
stackView.accessibilityLabel = label.text
}
以这种方式更新 stackView.accessibilityLabel
不会触发 VoiceOver 通知用户并允许达到您的目的.
Updating the stackView.accessibilityLabel
this way doesn't trigger VoiceOver to inform the user and allows to get your purpose.
但是,除非您重新排序呈现的元素.
However, I don't recommend to read out the title as the first element of a new page unless you reorder the presented elements.
VoiceOver 用户不会自然地猜到标题之前存在另一个元素:
VoiceOver users won't naturally guess that another element is present before the title :
- 他们可能找不到返回上一页的方法.
- 如果他们使用获取页面的第一个元素,他们可能会丢失4 根手指轻点,因为他们会得到后退按钮而不是标题.
- They may not find a way to get back to the previous page.
- They may be lost if they get the first element of the page with a 4 fingers simple-tap because they'll get the back button and not the title.
从技术上讲,您的问题已通过上面的一段代码解决,但从概念上讲,如果您仍想将标题作为第一个元素公开,我建议您对元素重新排序.
Technically, your problem is solved with the piece of code above but, conceptually, I suggest to reorder your elements if you still want to expose the title as the first element.
==========
编辑(解决方法)
关于技术问题,您在评论中说得对,由于 VoiceOver 读取标签,上述解决方案有效.
About the technical problem, you're right in your comment, this solution above works thanks to the label reading by VoiceOver.
我在您在初始帖子中提供的 git 分支中提交了一个解决方案.
I commited a solution in your git branch you gave in your initial post.
问题涉及 UIStackView,在这种情况下我无法解释,也无法按原样解决.
The problem deals with the UIStackView I cannot explain in this case and cannot solve neither as is.
为了达到您的目的,我为堆栈视图创建了一个 UIAccessibilityELement
,它可以完美地访问和公开,无需重复阅读后通知.
To reach your purpose, I created a UIAccessibilityELement
for the stackview that can be perfectly reached and exposed with no double reading with a postnotification.
我这样做是因为当标签在里面时我无法以编程方式获得 stackview 的新大小......也许创建一个 UIStackView 子类并进入它的 layoutSubviews
可能是诀窍?
I did that because I couldn't get programmatically the stackview new size when the labels are in... maybe creating a UIStackView subclass and get into its layoutSubviews
could be the trick ?
这个解决方案应该作为一种解决方法,但我不知道 UIStackview 出现这种行为的原因.
This solution should work as a workaround but I don't know the reason why this behavior appears with a UIStackview.
==========
编辑(解决方案)
问题在于 navigationItem
的 titleView
的创建方式.实现目标的最佳方式是:
The problem is the way the titleView
of the navigationItem
is created. The best way to achieve your purpose is to :
- 将 titleView 初始化为一个简单的
UIView
,其框架与堆栈视图的框架相同. - 在指定其框架和可访问性属性后,将堆栈视图添加为子视图.
- Initialize your titleView as a simple
UIView
whose frame is the same as the stackview's. - Add the stackview as a subview after having specified its frame and its accessibility properties.
在您的代码中按照以下步骤操作:
Follow the steps hereafter in your code :
在 stackview 属性中添加
.header
trait:
private lazy var stackView: UIStackView = {
let stackView = UIStackView(frame: .zero)
stackView.axis = .vertical
stackView.alignment = .center
stackView.distribution = .equalSpacing
stackView.isAccessibilityElement = true
stackView.accessibilityTraits = .header
return stackView
}()
更改switch...case..."代码部分中的 stackview case,如下所示:
Change the stackview case in your 'switch...case...' code section as below :
case .stackView:
label.text = "UIStackView"
label.sizeToFit()
stackView.addArrangedSubview(label)
label2.text = subtitle
label2.sizeToFit()
stackView.addArrangedSubview(label2)
stackView.frame.size.width = max(label.frame.width, label2.frame.width)
stackView.frame.size.height = label.frame.height + label2.frame.height
stackView.accessibilityLabel = label.text?.appending(", \(label2.text!)")
navigationItem.titleView = UIView(frame: stackView.frame)
navigationItem.titleView?.addSubview(stackView)
}
现在,postNotification
仅读取一次您的堆栈视图作为屏幕的第一个元素.
Now, the postNotification
reads out your stackview only once as the first element of your screen.
这篇关于聚焦非 UILabel titleView 时,VoiceOver 读取辅助功能标签两次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!