1

我有一个UISwitch内部 tableviewcell。切换发出网络请求。AUIActivityIndicator替换开关,直到响应完成。所以UX流程是这样的:

off --> loader --> on

在点击标签之前,可访问性如下所示:

label - value - hint
‘streaming - switch button off - double tap to toggle switch’

我的代码是这样的:

@IBAction func switchToggled(_ sender: Any) {
    toggle.isHidden = true
    activityIndicatorView.startAnimating()
    UIAccessibility.post(notification: .layoutChanged, argument: activityIndicatorView)

我还禁用了单元格本身的可访问性。

问题是可访问性将如下所示:

$switchValue - activityIndicatorLabel-activityIndicatorValue - switchLabel switchValue
off - streaming - in progress - streaming - switch button on

我不确定为什么在我将切换开关设置isHiddentrue并发布辅助功能通知后,辅助功能仍然会读取 ‍♂️</p>

我想从上面省略☝️并让它这样读:

$activityIndicatorLabel-activityIndicatorValue - switchLabel switchValue
streaming - in progress - streaming - switch button on

FWIW

UIAccessibility.post(notification: .screenChange, argument: activityIndicatorView)

获得所需的语音序列,但随后会产生新问题。那就是我听到“哔哔”的声音,这会使用户误以为他们在新屏幕中。

这个通知移动到正确的项目,而另一个没有,这很奇怪。我本来希望两者都会创建相同的订单,但他们不会


编辑:

我已经研究了如何在 Voiceover 说话时停止 Text to Speech,或者在 Swift 中反之亦然?

我正在观察UIAccessibilityElementFocusedNotification通知。我在userInfo.

▿ Optional<Dictionary<AnyHashable, Any>>
  ▿ some : 3 elements
    ▿ 0 : 2 elements
      ▿ key : AnyHashable("UIAccessibilityFocusedElementKey")
        - value : "UIAccessibilityFocusedElementKey"
      - value : <UIActivityIndicatorView: 0x113b59350; frame = (794 20; 24 24); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x2811a91e0>>
    ▿ 1 : 2 elements
      ▿ key : AnyHashable("UIAccessibilityAssistiveTechnologyKey")
        - value : "UIAccessibilityAssistiveTechnologyKey"
      - value : UIAccessibilityNotificationVoiceOverIdentifier
    ▿ 2 : 2 elements
      ▿ key : AnyHashable("UIAccessibilityUnfocusedElementKey")
        - value : "UIAccessibilityUnfocusedElementKey"
      - value : <MyModule.MySwitch: 0x113b59540; baseClass = UISwitch; frame = (769 16.5; 51 31); hidden = YES; opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x2811a9120>>

有两件事我不知道如何解决。

  1. 这三个事件并没有按顺序进行。它只是一个包含所有三个的通知。我想取消配音,因为开关没有焦点。我不希望人们阅读它。
  2. 答案仍然没有解释如何取消不需要的配音。
4

1 回答 1

0

不幸的是,Voice Over 有很多错误(在其存在之初,它要好得多,但随着后续 iOS 版本的变化,它变得更糟)。强迫它以不同的方式表现是很多“黑客行为”,并且对于新系统,它可能会再次以您不希望的方式表现。说了这么多,我将提出至少现在可以使用的解决方案。

在开始时,我必须说以编程方式暂停 VoiceOver 是不可能的,因为它会导致崩溃(检查这里)。就这样

UIAccessibility.post(notification: .pauseAssistiveTechnology, argument: UIAccessibility.AssistiveTechnologyIdentifier.notificationVoiceOver)

不会有帮助的。

使用 UISwitch 处理 UITableViewCell 的最佳方式是采用与 Apple 在 iPhone 设置中相同的方式(将 Voice Over 集中在整个单元格上)。所以你的开关不应该是可访问性元素。

现在发现最有趣的事情 - 如果 switch.isUserInteractionEnabled 标志设置为 true,那么双击单元格将不会调用

tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath)

或者

tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)

所以系统会以默认方式运行,并在滑块更改后直接读取滑块的新值。

但是,如果您将创建方法来设置新出列的单元格(在您的自定义单元格类中)并在那里编写类似的内容

func setup() {
    slider.isUserInteractionEnabled = !UIAccessibility.isVoiceOverRunning //if VO is running you can't normally tap slider so it won't affect user experience
    NotificationCenter.default.removeObserver(self)
    NotificationCenter.default.addObserver(self, selector: #selector(setSwitchAccessibility), name: UIAccessibility.voiceOverStatusDidChangeNotification, object: nil)
}

@objc func setSwitchAccessibility() {
    slider.isUserInteractionEnabled = !UIAccessibility.isVoiceOverRunning //without VO user should be able to interact with switch directly or / and by selecting cell
}

然后你的表委托将被调用,允许做一些自定义的事情。当 Voice Over 关闭时,观察画外音是允许处理切换的必要条件。

通过“自定义”,我理解在 willSelectRow 中显示活动指示器并将焦点移到那里

UIAccessibility.post(notification: .layoutChanged, argument: activityIndicatorView) 

并将可访问性值设置为 nil(在恢复 Voice Over 对单元格的焦点之前再次将其设置为滑块可访问性值)。

另外 - 从单元格中删除辅助功能值后,如果存在,则 Voice Over 将读取该单元格的辅助功能标签。在这种情况下,您需要通过此单元格的自定义属性(设置为 nil)临时覆盖默认的可访问性标签,以使其静音,使用类似的东西:

var labelToReturn: String? = ""

    override func accessibilityActivate() -> Bool {
        self.accessibilityValue = nil
        labelToReturn = nil
        return false
    }

    override var accessibilityLabel: String? {
        get {return labelToReturn == nil ? labelToReturn: super.accessibilityLabel}
        set {super.accessibilityLabel = newValue}
    }

labelToReturn请记住在从活动指示器中移除焦点之前更改为其他内容。

于 2020-02-07T13:53:50.933 回答