UIAccessibilityElement 在 UITableViewCell 内的长视图中聚焦问题
UIAccessibilityElement focusing issue within a long view inside a UITableViewCell
我有一个 UITableViewCell
包含一个视图,该视图具有一些子辅助功能元素。画面很长,比单屏还长
当用户左右滑动以浏览子元素时,selected 元素有时会在屏幕之外。当他稍后双击时,他无法触发此类元素的动作。
为什么不起作用?如何让它正常工作?
为什么 selected 元素有时会在屏幕外?如何在屏幕上显示?
这里是 sample code.
- 当双击正常工作时,您将在 Xcode 控制台中看到一个登录。
- 这是一个过度简化的示例。我不能在真实应用程序中使用单独的单元格。将其视为带有链接的富文本视图,用户使用左右轻弹即可找到 select 个链接。
Why does it not work? How to make it work correctly?
在 VoiceOver OFF 的情况下,tap
函数会在您触摸元素后打印该元素 AND 如果它可见,因为点击手势只发生在屏幕上。
在 VoiceOver ON ✅ 的情况下,即使屏幕 reader 能够读出屏幕外的先前标签,您也应该以同样的方式思考:当你用一根手指双击屏幕外的元素,这个手势不能用 GestureRecognizer
.
处理
一种解决方案是使用 accessibilityActivate 方法,该方法在 a11y 元素上发生双击时触发。
我建议创建一个标签 class,您可以在其中实现此功能:
class myLabel:UILabel {
init(frame: CGRect, index: Int) {
super.init(frame: frame)
text = "\(index)"
isAccessibilityElement = true
isUserInteractionEnabled = true
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tap)))
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func accessibilityActivate() -> Bool {
print(text!)
return true
}
@objc func tap(sender: UITapGestureRecognizer) {
guard sender.state == .recognized else { return }
print(sender.view!)
}
}
LongView
class 具有以下代码来定义其行为:
class LongView: UIView {
override var isAccessibilityElement: Bool {
get { return false }
set { }
}
override var accessibilityElementsHidden: Bool {
get { return false }
set { }
}
override init(frame: CGRect) {
super.init(frame: frame)
let screenWidth = UIScreen.main.bounds.width
var x: CGFloat = 20
var y: CGFloat = 20
let width: CGFloat = 200
let height: CGFloat = 40
let spacing: CGFloat = 20
for index in 0..<20 {
let label = myLabel(frame: CGRect(x: x, y: y, width: width, height: height),
index: index)
addSubview(label)
x += width + spacing
if x + width > screenWidth {
y += height + spacing
x = spacing
}
}
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
override var intrinsicContentSize: CGSize {
CGSize(width: UIScreen.main.bounds.width,
height: subviews.map { [=11=].frame.maxY }.max()! + 20)
}
}
而table视图单元格class如下:
class Cell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
let longView = LongView()
longView.accessibilityElementsHidden = false
contentView.addSubview(longView)
longView.translatesAutoresizingMaskIntoConstraints = false
longView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
longView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
longView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
longView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
现在,您可以注意到:
- VoiceOver 关闭时会触发
GestureRecognizer
功能。
- 当 VoiceOver 在屏幕上存在或不存在的每个标签上打开时,将处理单指双击手势。
我不确定是否所有添加的行都是实现您的目标所必需的,但这是在 UITableViewCell 内的长视图中解决 UIAccessibilityElement 聚焦问题的基本原理。
我有一个 UITableViewCell
包含一个视图,该视图具有一些子辅助功能元素。画面很长,比单屏还长
当用户左右滑动以浏览子元素时,selected 元素有时会在屏幕之外。当他稍后双击时,他无法触发此类元素的动作。
为什么不起作用?如何让它正常工作?
为什么 selected 元素有时会在屏幕外?如何在屏幕上显示?
这里是 sample code.
- 当双击正常工作时,您将在 Xcode 控制台中看到一个登录。
- 这是一个过度简化的示例。我不能在真实应用程序中使用单独的单元格。将其视为带有链接的富文本视图,用户使用左右轻弹即可找到 select 个链接。
Why does it not work? How to make it work correctly?
在 VoiceOver OFF 的情况下,tap
函数会在您触摸元素后打印该元素 AND 如果它可见,因为点击手势只发生在屏幕上。
在 VoiceOver ON ✅ 的情况下,即使屏幕 reader 能够读出屏幕外的先前标签,您也应该以同样的方式思考:当你用一根手指双击屏幕外的元素,这个手势不能用 GestureRecognizer
.
处理
一种解决方案是使用 accessibilityActivate 方法,该方法在 a11y 元素上发生双击时触发。
我建议创建一个标签 class,您可以在其中实现此功能:
class myLabel:UILabel {
init(frame: CGRect, index: Int) {
super.init(frame: frame)
text = "\(index)"
isAccessibilityElement = true
isUserInteractionEnabled = true
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tap)))
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func accessibilityActivate() -> Bool {
print(text!)
return true
}
@objc func tap(sender: UITapGestureRecognizer) {
guard sender.state == .recognized else { return }
print(sender.view!)
}
}
LongView
class 具有以下代码来定义其行为:
class LongView: UIView {
override var isAccessibilityElement: Bool {
get { return false }
set { }
}
override var accessibilityElementsHidden: Bool {
get { return false }
set { }
}
override init(frame: CGRect) {
super.init(frame: frame)
let screenWidth = UIScreen.main.bounds.width
var x: CGFloat = 20
var y: CGFloat = 20
let width: CGFloat = 200
let height: CGFloat = 40
let spacing: CGFloat = 20
for index in 0..<20 {
let label = myLabel(frame: CGRect(x: x, y: y, width: width, height: height),
index: index)
addSubview(label)
x += width + spacing
if x + width > screenWidth {
y += height + spacing
x = spacing
}
}
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
override var intrinsicContentSize: CGSize {
CGSize(width: UIScreen.main.bounds.width,
height: subviews.map { [=11=].frame.maxY }.max()! + 20)
}
}
而table视图单元格class如下:
class Cell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
let longView = LongView()
longView.accessibilityElementsHidden = false
contentView.addSubview(longView)
longView.translatesAutoresizingMaskIntoConstraints = false
longView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
longView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
longView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
longView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
现在,您可以注意到:
- VoiceOver 关闭时会触发
GestureRecognizer
功能。 - 当 VoiceOver 在屏幕上存在或不存在的每个标签上打开时,将处理单指双击手势。
我不确定是否所有添加的行都是实现您的目标所必需的,但这是在 UITableViewCell 内的长视图中解决 UIAccessibilityElement 聚焦问题的基本原理。