【问题标题】:How to catch accessibility focus changed?如何捕捉可访问性焦点的变化?
【发布时间】:2019-06-17 19:21:41
【问题描述】:

我想捕捉可访问性焦点的变化。

我搜索并尝试了accessibilityElementDidBecomeFocused,但在光标更改后没有触发。我想为按钮添加值,并在光标更改后删除此值。

我的代码是这样的:

override func viewDidLoad() {
    flashButton.accessibilityLabel = "Change the flash status"
    flashButton.accessibilityTraits = [.button]
    flashButton.accessibilityIdentifier = "flashButton"
}

@IBAction func flashButtonTapped(_ sender: Any) {
    var currentFlashStatus = "off"
    guard let device =  AVCaptureDevice.default(AVCaptureDevice.DeviceType.builtInWideAngleCamera, for: AVMediaType.video, position: .back) else { return }
    guard device.hasTorch else { return }
    do {
        try device.lockForConfiguration()
        if device.torchMode == .on {
            device.torchMode = .off
            flashButton.image = UIImage(named: "flashOffIcon")
            currentFlashStatus = "off"
        } else {
            do {
                try device.setTorchModeOn(level: 1.0)
                flashButton.image = UIImage(named: "flashOnIcon")
                currentFlashStatus = "on"
            } catch {
                print(error)
            }
        }
        device.unlockForConfiguration()
    } catch {
        print(error)
    }
    flashButton.accessibilityLabel = "Turned \(currentFlashStatus) the flash"
}

首先,它显示“更改闪光灯状态”,如果我双击它会显示“打开闪光灯状态”,这是正确的。

如果我改变光标并回到闪光按钮,它应该说再次改变闪光状态。但它说“打开闪光灯状态”

我怎样才能做到这一点?

【问题讨论】:

    标签: ios swift accessibility


    【解决方案1】:

    我搜索并尝试了accessibilityElementDidBecomeFocused,但在光标更改后没有触发。

    如果您想使用UIAccessibilityFocus 非正式协议方法,您必须直接在您的对象中覆盖它们,而不是在视图控制器中(参见this answer。例如,创建UIButton 的子类:

    import UIKit
    
    class FlashButton: UIButton {}
    
    extension FlashButton {
    
        override open func accessibilityElementDidBecomeFocused() {
        // Actions to be done when the element did become focused.
        }
    }
    

    如果我改变光标并回到闪光按钮,它应该说再次改变闪光状态。

    无论您选择闪烁按钮多少次,都应始终先读出所需状态,然后再说更改其值。

    后面的代码中提供了一个例子:

    class FlashButton: UIButton {
    
        private var intStatus: Bool = false
        private var a11yLabelStatus: String = "off"
    
        var status: Bool {
            get { return intStatus }
            set(newValue) { intStatus = newValue }
        }
    }
    
    extension FlashButton {
    
        override open func accessibilityElementDidBecomeFocused() {
        // Actions to be done when the element did become focused.
        }
    
        override open func accessibilityElementDidLoseFocus() {
        // Actions to be done when the element did lose focus.
        }
    
        //This native a11y function replaces your defined IBAction to change and read out the flash status.
        override func accessibilityActivate() -> Bool {
    
            intStatus = (intStatus == true) ? false : true
            a11yLabelStatus = (intStatus == true) ? "on" : "off"
    
            UIAccessibility.post(notification: .announcement,
                                 argument: "flash status is " + a11yLabelStatus)
            return true
        }
    
        override var accessibilityLabel: String? {
            get { return "the flash status is " + a11yLabelStatus }
            set { }
        }
    
        override var accessibilityHint: String? {
            get { return "double tap to change the value." }
            set { }
        }
    }
    

    我怎样才能做到这一点?

    您可以尝试UIAccessibilityFocus 非正式协议来捕捉焦点变化,或者您只需使用上面的代码 sn-p 来更改可访问性元素的状态:您可以将两者结合起来,在您的编码环境中调整这些概念取决于您。 ;o)

    如果还不够,请查看this site 专门为 a11y 开发人员提供的代码 sn-ps 和插图,以找到适合您的实施的另一种解决方案。

    【讨论】:

    • 非常感谢您的回复。但我认为如果它是 UIBarButtonItem 则存在错误。如果它是 UIButton 的子类,它工作得很好。但如果是 UIBarButtonItem 的子类,accessibilityElementDidBecomeFocused 不会触发。