如何将可访问性集中在 UISegmentedControl 中的特定部分
How to Focus Accessibility On A Particular Segment in A UISegmentedControl
好的。 This answer 帮助很大。当屏幕显示时,我可以 select 辅助功能项目。我只是添加
UIAccessibility.post(notification: .layoutChanged, argument: <a reference to the UI item to receive focus>)
到我的 viewWillAppear() 方法的末尾,项目获得焦点。
但是,在我的一个屏幕中,我想要获得焦点的项目是一个 UISegmentedControl,并且在聚焦时,它总是 select 第一个项目,无论哪个是 select编辑。由于我遵循了出色的建议 here,我为控件中的每个项目都设置了一个辅助功能标签,并且我希望我的注意力集中在 selected.
的任何部分上
有办法吗?通常,我尽量避免 "hacky" 解决方案(就像我刚才提到的那个),但我愿意考虑任何事情。
谢谢!
更新:雪上加霜的是,我也对我想要 selected 的物品有疑问 selected,一秒钟后,屏幕将 selection 跳到第一项。这可能是第二个问题的主题。
为了重现问题,我创建了一个空白项目如下:
解决方案是采用selectedIndex
来显示select编辑的段并提供适当的段对象 对于 VoiceOver notification:很简单,不是吗?
我天真地认为用 selectedIndex
获取分段控制子视图数组中的子视图就可以完成工作,但这绝对不可能,因为 子视图可以在这个数组中移动 作为以下快照突出显示 (例如红色框的第一个元素):
识别唯一段的唯一方法是它的框架,所以我选择分段控件索引和 selected 段的框架,将它们传递给前一个视图控制器。
这将允许显示 (索引) 并读出 (标识通知对象的框架) 适当的 selected 段,当这个屏幕将在转换后出现。
以下是包含 'Next Screen' 按钮的视图控制器的代码片段:
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: { [=11=].frame.origin.x < .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 ([=11=].frame == self.segmentFrame) {
UIAccessibility.post(notification: .screenChanged,
argument: [=11=])
}
})
}
}
@objc func segmentedControlValueChanged(_ notif: NSNotification) {
delegate?.updateSegmentIndex(mySegmentedControl.selectedSegmentIndex,
withFrame: segmentFrames[mySegmentedControl.selectedSegmentIndex]!) }
}
最终结果如下:
- 双击进入下一个屏幕。
- Select 关注第二段的下一个元素。
- 双击 select 焦点元素。
- 由于导航控制器 iOS 本机已知的
Z gesture
,可以返回上一屏幕。委托传递 selected 段的索引和框架。
- 双击进入下一个屏幕。
- 之前 selected 的片段由 VoiceOver 读出并且仍然 selected。
您现在可以在 UISegmentedControl 中的特定段上关注可访问性,遵循这个基本原理。
I try to avoid "hacky" solutions (like the one I just referenced), but I'm willing to consider anything.
不幸的是,这个解决方案是一个 hacky 的...抱歉。但是,它有效,我在其他任何地方都找不到另一个:将其视为个人修复,除非你得到一个更干净的共享? ;o)
UPDATE... That's probably a topic for a second question.
我无法重现您的更新行为:如果您为此问题创建专门的主题,请添加最详细的代码和上下文,以便提供最准确的解决方案。
好的。 This answer 帮助很大。当屏幕显示时,我可以 select 辅助功能项目。我只是添加
UIAccessibility.post(notification: .layoutChanged, argument: <a reference to the UI item to receive focus>)
到我的 viewWillAppear() 方法的末尾,项目获得焦点。
但是,在我的一个屏幕中,我想要获得焦点的项目是一个 UISegmentedControl,并且在聚焦时,它总是 select 第一个项目,无论哪个是 select编辑。由于我遵循了出色的建议 here,我为控件中的每个项目都设置了一个辅助功能标签,并且我希望我的注意力集中在 selected.
的任何部分上有办法吗?通常,我尽量避免 "hacky" 解决方案(就像我刚才提到的那个),但我愿意考虑任何事情。
谢谢!
更新:雪上加霜的是,我也对我想要 selected 的物品有疑问 selected,一秒钟后,屏幕将 selection 跳到第一项。这可能是第二个问题的主题。
为了重现问题,我创建了一个空白项目如下:
解决方案是采用selectedIndex
来显示select编辑的段并提供适当的段对象 对于 VoiceOver notification:很简单,不是吗?
我天真地认为用 selectedIndex
获取分段控制子视图数组中的子视图就可以完成工作,但这绝对不可能,因为 子视图可以在这个数组中移动 作为以下快照突出显示 (例如红色框的第一个元素):
这将允许显示 (索引) 并读出 (标识通知对象的框架) 适当的 selected 段,当这个屏幕将在转换后出现。
以下是包含 'Next Screen' 按钮的视图控制器的代码片段:
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: { [=11=].frame.origin.x < .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 ([=11=].frame == self.segmentFrame) {
UIAccessibility.post(notification: .screenChanged,
argument: [=11=])
}
})
}
}
@objc func segmentedControlValueChanged(_ notif: NSNotification) {
delegate?.updateSegmentIndex(mySegmentedControl.selectedSegmentIndex,
withFrame: segmentFrames[mySegmentedControl.selectedSegmentIndex]!) }
}
最终结果如下:
- 双击进入下一个屏幕。
- Select 关注第二段的下一个元素。
- 双击 select 焦点元素。
- 由于导航控制器 iOS 本机已知的
Z gesture
,可以返回上一屏幕。委托传递 selected 段的索引和框架。 - 双击进入下一个屏幕。
- 之前 selected 的片段由 VoiceOver 读出并且仍然 selected。
您现在可以在 UISegmentedControl 中的特定段上关注可访问性,遵循这个基本原理。
I try to avoid "hacky" solutions (like the one I just referenced), but I'm willing to consider anything.
不幸的是,这个解决方案是一个 hacky 的...抱歉。但是,它有效,我在其他任何地方都找不到另一个:将其视为个人修复,除非你得到一个更干净的共享? ;o)
UPDATE... That's probably a topic for a second question.
我无法重现您的更新行为:如果您为此问题创建专门的主题,请添加最详细的代码和上下文,以便提供最准确的解决方案。