UIAccessibilityElement在UITableViewCell内的长期视图中聚焦问题

UIAccessibilityElement在UITableViewCell内的长期视图中聚焦问题,uitableview,voiceover,Uitableview,Voiceover,我有一个UITableViewCell,其中包含一个具有一些子可访问性元素的视图。视图相当长,比单个屏幕长 当用户向左和向右轻弹以浏览子元素时,所选元素有时会脱离屏幕。当他稍后双击时,他无法触发此类元素的操作 为什么它不起作用?如何使其正确工作 为什么所选元素有时不在屏幕上?如何在屏幕上制作 这是你的电话号码 当双击正常工作时,您将在Xcode控制台中看到一个日志 这是一个过于简化的示例。我不能在真正的应用程序中使用单独的单元格。可以将其视为一个包含链接的富文本视图,用户使用左键和右键选择链接

我有一个
UITableViewCell
,其中包含一个具有一些子可访问性元素的视图。视图相当长,比单个屏幕长

当用户向左和向右轻弹以浏览子元素时,所选元素有时会脱离屏幕。当他稍后双击时,他无法触发此类元素的操作

为什么它不起作用?如何使其正确工作

为什么所选元素有时不在屏幕上?如何在屏幕上制作

这是你的电话号码

  • 当双击正常工作时,您将在Xcode控制台中看到一个日志
  • 这是一个过于简化的示例。我不能在真正的应用程序中使用单独的单元格。可以将其视为一个包含链接的富文本视图,用户使用左键和右键选择链接 为什么它不起作用?如何使其正确工作

    关闭画外音时❌, 触摸元素后,
    tap
    功能将打印该元素,如果该元素可见,则打印该元素,因为只有在屏幕上才会出现轻触手势

    使用画外音✅, 即使屏幕阅读器能够读出屏幕外以前的标签,您也应该以同样的方式思考:当您用一个手指双击屏幕外的元素时,手势无法用
    手势识别器处理

    解决方案可以是使用在a11y元件上发生双击时触发的方法

    我建议创建一个label类,在其中实现此函数:

    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 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 { $0.frame.maxY }.max()! + 20)
        }
    }
    
    现在,您可以注意到:

    • 当画外音关闭时,将触发
      手势识别器
      功能

    • 当画外音出现在屏幕上或屏幕上的每个标签上时,将处理单指双击手势。
      accessibilityActivate
      技巧有效,谢谢!然而,我仍然有一些其他的问题,这些问题与所选元素不在屏幕中有关。您知道为什么所选元素有时不在屏幕上吗?如何在屏幕上显示?@an0:在提供信息之前,我询问了您希望的行为,您指出了我回答的双击问题,但帖子将95%相同,样本代码完全相同。可能会被标记为重复。另外,我指出双击不起作用是因为元素在屏幕外,但我承认我没有明确说明,当我说“为什么它不起作用”时,我的意思是为什么元素在屏幕外。我接受你的回答。如果你知道这个根本问题的答案,如果你能把它添加到这里,我将不胜感激。再次感谢。@an0:我不知道这个问题的解决方案,但如果它是您要解决的主要问题,我会花时间搜索,就像我在双击时做的一样,我也不知道@an0:如果您想在表视图单元格中插入带有链接的富文本,允许用户通过左键和右键选择它们,我强烈建议删除“LongView”,并添加一个带有链接的属性字符串,与我视图中的此架构选择相比,VoiceOver更容易处理这些链接⟹
      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") }
      }