如何使用画外音确定当前聚焦的 UITableViewCell 的索引路径?

How can I determine the index path for the currently focused UITableViewCell using Voice Over?

我有一个动态的 UITableView。对于每个单元格,我添加一个 UIAccessibilityCustomAction。当动作触发时,我需要知道索引路径,以便我可以做出相应的响应并更新我的模型。

tableView(_:cellForRowAt:) 中,我像这样添加我的 UIAccessibilityCustomAction...

cell.accessibilityCustomActions = [
    UIAccessibilityCustomAction(
        name: "Really Bad Name",
        target: self,
        selector: #selector(doSomething)
    )
]

我试过UIAccessibility.focusedElement没用...

@objc private func doSomething() {
    let focusedCell = UIAccessibility.focusedElement(using: UIAccessibility.AssistiveTechnologyIdentifier.notificationVoiceOver) as! UITableViewCell
    // Do something with the cell, like find the indexPath.
}

问题是投射到单元格失败。调试器说 return 值类型实际上是 UITableTextAccessibilityElement,我找不到相关信息。

When the action fires, I need to know the index path so I can respond accordingly and update my model.

达到目标的最佳方式是使用UIAccessibilityFocus informal protocol方法,直接在对象中覆盖它们(table 查看单元格 class 在你的情况下):当自定义操作被触发时,你将能够捕获所需的索引路径。

我建议查看 处理捕获可访问性焦点更改,其中包含详细的解决方案和代码片段(如果需要)。

示例片段...

class SomeCell: UITableViewCell

    override open func accessibilityElementDidBecomeFocused() {
        // Notify view controller however you want (delegation, closure, etc.)
    }

}

我最终不得不自己解决这个问题以避开 Apple 错误。您可能已经解决了这个问题,但这是一个类似于您第一个建议的选项。

func accessibilityCurrentlySelectedIndexPath() -> IndexPath? {
    let focusedElement:Any

    if let voiceOverObject = UIAccessibility.focusedElement(using: UIAccessibility.AssistiveTechnologyIdentifier.notificationVoiceOver) {
        focusedElement = voiceOverObject
    } else if let switchControlObject = UIAccessibility.focusedElement(using: UIAccessibility.AssistiveTechnologyIdentifier.notificationSwitchControl) {
        focusedElement = switchControlObject
    } else {
        return nil
    }

    let accessibilityScreenFrame:CGRect
    if let view = focusedElement as? UIView {
        accessibilityScreenFrame = view.accessibilityFrame
    } else if let accessibilityElement = focusedElement as? UIAccessibilityElement {
        accessibilityScreenFrame = accessibilityElement.accessibilityFrame
    } else {
        return nil
    }

    
    let tableViewPoint = UIApplication.shared.keyWindow!.convert(accessibilityScreenFrame.origin, to: tableView)
    return tableView.indexPathForRow(at: tableViewPoint)
}

我们在这里所做的实质是获取聚焦的矩形(在屏幕坐标中),然后将其转换回 table 视图的坐标 space。然后我们可以向 table 视图询问包含该点的索引路径。简单而贴心,但如果您使用 multi-window,您可能需要将 UIApplication.shared.keyWindow! 换成更合适的东西。请注意,当我们处理 UIAccessibilityElement 时,我们会处理您遇到的元素是 UITableTextAccessibilityElement 的问题,因为 UITableTextAccessibilityElement 是私有的内部 Apple class.