2

我遇到了 VoiceOver 的一个奇怪问题。

目标:

  • 设置一个UIStackView包含多个UILabel的作为我的navigationItem.titleView
  • 将堆栈视图标记为可访问性元素并将其设置accessibilityLabel为适当的值。
  • UIAccessibility.post(notification: .screenChanged, argument: navigationItem.titleView)通过调用inside将堆栈视图设置为初始 VoiceOver 焦点viewDidAppear(animated:)

预期结果:

  • 当视图控制器出现时,焦点似乎在标题视图上,并且 VoiceOver 会读取可访问性标签的内容一次。

实际结果:

  • VoiceOver 开始阅读辅助功能标签的内容,然后中途(或有时在完成后)继续第二次阅读。

如果我设置navigationItem.titleViewUILabel.

有谁知道为什么会这样?这是iOS中的错误吗?

我在这里建立了一个简单的项目来演示这个问题: https ://github.com/rzulkoski/Focus-TitleView-Bug

4

1 回答 1

1

您第二次阅读标题的原因在于您的代码。

在您的viewDidLoad中,您设置 VoiceOver 自动读出的 stackview 可访问性标签以通知用户更改。

接下来,您可以viewDidAppear通过 VoiceOver 自然读出的帖子来通知这一变化。

为了防止这种行为,只需stackView.accessibilityLabel = label.text在您的setupNavigationItem函数中删除并将此代码段添加到您的私有惰性 var 标签 init 中:

if (self.view.subviews.contains(stackView)) {
        stackView.accessibilityLabel = label.text
}

以这种方式更新stackView.accessibilityLabel不会触发 VoiceOver 通知用户并允许达到您的目的。

但是,我不建议将标题作为新页面的第一个元素读出,除非您对呈现的元素重新排序。

VoiceOver 用户不会自然地猜测标题之前存在另一个元素:

  • 他们可能找不到返回上一页的方法。
  • 如果他们用4 根手指轻按来获得页面的第一个元素,他们可能会丢失,因为他们将获得后退按钮而不是标题。

从技术上讲,您的问题已通过上面的代码解决,但从概念上讲,如果您仍想将标题作为第一个元素公开,我建议重新排序您的元素。

==========

编辑(解决方法)

关于技术问题,您的评论是对的,上面的解决方案得益于 VoiceOver 的标签阅读。

我在您在初始帖子中提供的 git 分支中提交了一个解决方案。

问题涉及 UIStackView,在这种情况下我无法解释,也无法按原样解决。

为了达到您的目的,我UIAccessibilityELement为 stackview 创建了一个可以完美地达到和公开的堆栈视图,无需通过 postnotification 进行重复阅读。

我这样做是因为当标签位于时我无法以编程方式获得stackview的新大小......也许创建一个 UIStackView 子类并进入它layoutSubviews可能是诀窍?

该解决方案应该可以作为一种解决方法,但我不知道 UIStackview 出现此行为的原因。

==========

编辑(解决方案)

问题是创建的titleView方式navigationItem。实现目标的最佳方法是:

  • 将您的 titleView 初始化为一个简单UIView的框架,其框架与 stackview 的相同。
  • 在指定其框架及其可访问性属性后,将 stackview 添加为子视图。

请按照以下代码中的步骤操作:

  • .header在 stackview 属性中添加特征:

    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 .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 的 stackview 只会读出一次。

于 2019-03-02T08:08:24.523 回答