【问题标题】:How to Focus Accessibility On A Particular Segment in A UISegmentedControl如何将可访问性集中在 UISegmentedControl 中的特定段上
【发布时间】:2018-12-14 13:45:10
【问题描述】:

好的。 This answer 有很大帮助。我可以在显示屏幕时选择辅助功能项目。我只是添加

UIAccessibility.post(notification: .layoutChanged, argument: <a reference to the UI item to receive focus>)

到我的 viewWillAppear() 方法的末尾,项目获得焦点。

但是,在我的一个屏幕中,我想要获得焦点的项目是 UISegmentedControl,并且当获得焦点时,它总是选择第一个项目,无论选择哪一个。由于我遵循了出色的建议 here,因此我为控件中的每个项目都有一个可访问性标签,并且我希望我的重点从选择的任何部分开始。

有没有办法做到这一点?作为一项规则,我尽量避免使用“hacky”解决方案(就像我刚才提到的那样),但我愿意考虑任何事情。

谢谢!

更新: 为了雪上加霜,我也遇到了我要选择的项目被选中的问题,然后一秒钟后,屏幕跳转选择第一项。这可能是第二个问题的主题。

【问题讨论】:

  • 只是补充一下:我尝试直接访问子视图(以前的黑客攻击),并发送带有指向所选子视图的指针的通知,但它不起作用。它选择了错误的片段。

标签: ios swift uiaccessibility


【解决方案1】:

我创建了一个空白项目如下重现问题:

解决方案是使用selectedIndex 显示选定的段并VoiceOver notification 提供适当的段对象:很简单,不是吗?

我天真地认为使用selectedIndex 获取分段控制子视图数组中的子视图可以完成这项工作,但这绝对不可能,因为子视图可以在此数组内移动,如下面的快照突出显示(例如红框的第一个元素) 识别唯一段的唯一方法是它的框架,所以我拾取分段控制索引和选定段的框架,以将它们传递给前一个视图控制器。

这将允许显示(索引)并读出(标识通知对象的框架)当此屏幕将在转换后出现时适当的选定段.

以下是包含“下一个屏幕”按钮的视图控制器的代码 sn-ps:

class SOFSegmentedControl: UIViewController, UpdateSegmentedIndexDelegate {

    var segmentIndex = 0
    var segmentFrame = CGRect.zero


    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        if let segueName = segue.identifier {
            if (segueName == "SegmentSegue") {
                if let destVC = segue.destination as? SOFSegmentedControlBis {

                    destVC.delegate = self
                    destVC.segmentIndex = segmentIndex
                    destVC.segmentFrame = segmentFrame
                }
            }
        }
    }


    @IBAction func buttonAction(_ sender: UIButton) { self.performSegue(withIdentifier: "SegmentSegue", sender: sender) }


    func updateSegmentIndex(_ index: Int, withFrame frame: CGRect) {

        segmentIndex = index
        segmentFrame = frame
    }
}

...对于显示分段控件的视图控制器:

protocol UpdateSegmentedIndexDelegate: class { 
    func updateSegmentIndex(_ index: Int, withFrame frame: CGRect) 
}


class SOFSegmentedControlBis: UIViewController {

    @IBOutlet weak var mySegmentedControl: UISegmentedControl!

    var delegate: UpdateSegmentedIndexDelegate?
    var segmentFrame = CGRect.zero
    var segmentIndex = 0
    var segmentFrames = [Int:CGRect]()


    override func viewDidLoad() {
        super.viewDidLoad()

        mySegmentedControl.addTarget(self,
                                     action: #selector(segmentedControlValueChanged(_:)),
                                     for: .valueChanged)

        mySegmentedControl.selectedSegmentIndex = segmentIndex
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        print(mySegmentedControl.subviews)

        let sortedFrames = mySegmentedControl.subviews.sorted(by: { $0.frame.origin.x < $1.frame.origin.x})

        for (index, segment) in sortedFrames.enumerated() { segmentFrames[index] = segment.frame }

        if (self.segmentFrame == CGRect.zero) {
            UIAccessibility.post(notification: .screenChanged,
                                 argument: mySegmentedControl)
        } else {
            mySegmentedControl.subviews.forEach({
                if ($0.frame == self.segmentFrame) {
                    UIAccessibility.post(notification: .screenChanged,
                                         argument: $0)
                }
            })
        }
    }


    @objc func segmentedControlValueChanged(_ notif: NSNotification) {

        delegate?.updateSegmentIndex(mySegmentedControl.selectedSegmentIndex,
                                     withFrame: segmentFrames[mySegmentedControl.selectedSegmentIndex]!) }
    }

最终结果如下:

  1. 双击可转到下一个屏幕。
  2. 选择下一个元素以聚焦第二个片段。
  3. 双击以选择焦点元素。
  4. 感谢Z gesture,iOS 自带导航控制器,可以返回上一个屏幕。委托传递所选段的索引和框架。
  5. 双击可转到下一个屏幕。
  6. 之前选择的片段被 VoiceOver 读出并且仍然被选中。

您现在可以将可访问性重点放在 UISegmentedControl 中的特定段上。

我尽量避免使用“hacky”解决方案(比如我刚才提到的那个),但我愿意考虑任何事情。

不幸的是,这个解决方案很老套……抱歉。但是,它有效,我在其他任何地方都找不到另一个:除非您找到更清洁的共享,否则将其视为个人修复? ;o)

更新...这可能是第二个问题的主题。

我无法重现您更新的行为:如果您为此问题创建了专门的主题,请添加最详细的代码和上下文,以便提供最准确的解决方案。

【讨论】:

    猜你喜欢
    • 2012-02-08
    • 2017-05-28
    • 2013-10-08
    • 1970-01-01
    • 2018-02-02
    • 1970-01-01
    • 2021-11-29
    • 2016-06-20
    • 2016-07-10
    相关资源
    最近更新 更多