【问题标题】:Make nested collection views with large cells accessible with VoiceOver使带有大单元格的嵌套集合视图可通过 VoiceOver 访问
【发布时间】:2018-01-07 04:03:24
【问题描述】:

在我目前正在开发的应用程序中,有一个嵌套的集合视图设置。外部集合视图包含可垂直滚动的大单元格,每个单元格包含另一个具有较小单元格的集合视图(子集合视图中的布局不同,这就是为什么有多个)。

从视觉上看,一切正常,但我遇到了 Voice Over 的问题:当我到达第一个子集合视图中的最后一项(即外部集合视图的第一个单元格的最后一项)时,我无法通过滑动选择下一个项目。取而代之的是,iOS 发出的声音好像已到达最后一项。

我可以三指滑动向下滚动,然后选择下一个元素,但这显然不是必需的。选择最后一个元素并以相反的顺序返回按预期工作。

问题似乎只在最初只有一个单元格(外部集合视图的)可见时才会出现。如果多个单元格可见,则一切正常。但是,我无法更改外部单元格的大小,因为这会完全改变布局。

我在下面创建了一个示例视图控制器来演示该问题。项目中的两个集合视图是相同的,只是单元格的大小不同。第一个具有较小单元格的集合视图按预期工作。第二个没有(滑动以选择下一个单元格时,iOS 会在选择最后一个可见单元格时播放“哔”声,即使还有更多的单元格向下)。

所以,我的问题是:

  • 如何使第二个集合视图的行为与第一个一样?
  • 如何使第二个集合视图中的单元格更靠下,可通过水平滑动访问?

到目前为止我尝试过的解决方案:

  • 一个 SO 帖子建议为嵌套集合视图创建一个包装器视图。这似乎没有什么区别。
  • 我尝试在集合视图的自定义子类中自己实现 UIAccessibilityContainer 协议。这似乎以奇怪的方式破坏了滚动。
  • 在随机位置放置“布局更改”通知,看看是否有帮助(没有帮助)

编辑: 演示该问题的 ViewController 的完整代码:

class ViewController: UIViewController, UICollectionViewDataSource {
    let outerCollectionView = UICollectionView(frame: CGRect(x: 0, y: 40, width: 320, height: 250), collectionViewLayout: UICollectionViewFlowLayout())

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .green
        outerCollectionView.backgroundColor = .blue

        (outerCollectionView.collectionViewLayout as! UICollectionViewFlowLayout).itemSize = CGSize(width: 250, height: 300)
        outerCollectionView.register(OuterCell.self, forCellWithReuseIdentifier: "outerCell")
        view.addSubview(outerCollectionView)
        outerCollectionView.dataSource = self
    }

    func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 4 }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "outerCell", for: indexPath) as! OuterCell
        cell.outerIndex = indexPath.row + 1
        return cell
    }
}

class OuterCell: UICollectionViewCell, UICollectionViewDataSource {
    var innerCollectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: 300, height: 500), collectionViewLayout: UICollectionViewFlowLayout())
    var outerIndex: Int = 0

    override init(frame: CGRect) {
        super.init(frame: frame)
        (innerCollectionView.collectionViewLayout as! UICollectionViewFlowLayout).itemSize = CGSize(width: 140, height: 80)
        innerCollectionView.backgroundColor = .yellow
        innerCollectionView.register(InnerCell.self, forCellWithReuseIdentifier: "innerCell")
        contentView.addSubview(innerCollectionView)
        innerCollectionView.dataSource = self
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("unused")
    }
    func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 }
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 3 }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "innerCell", for: indexPath) as! InnerCell
        cell.label.text = "Cell \(outerIndex) / \(indexPath.item+1)"
        return cell
    }
}

class InnerCell: UICollectionViewCell {
    let label = UILabel(frame: CGRect(origin: .zero, size: CGSize(width: 100, height: 30)))

    override init(frame: CGRect) {
        super.init(frame: frame)
        contentView.backgroundColor = .white
        contentView.addSubview(label)
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("unused")
    }
}

编辑:这是一个显示问题的视频:https://vimeo.com/229249955(请注意,我在那里添加了一些描述)。

【问题讨论】:

  • 你可以在这里发布你的代码而不是外部资源吗?
  • 我可以发布视图控制器的代码,但如果没有故事板,它就没有多大用处。我还是应该发布它吗?
  • 在 Stack Overflow 上发帖时,请尝试发Minimal, Complete and Verifiable example
  • 我发布的 xcode 项目是我认为最小、完整和可验证的项目。我知道我将它作为 zip 发布在其他地方并不理想,但我无法将 xcode 项目直接附加到 SO 帖子...
  • 用代码重写了 UI,因此我可以发布直接重现问题所需的所有内容。

标签: ios uicollectionview accessibility voiceover


【解决方案1】:

据我了解,问题是一旦到达内部集合视图中的最后一个单元格,您就无法滚动到外部集合视图中的下一个单元格。但是,三指滑动可以。

这是因为collection view 上的bounce 属性。尝试关闭内部集合视图的反弹属性。

在上面的代码中,在 OuterCell 的 init 方法中添加如下代码行。

innerCollectionView.bounces = false

【讨论】:

  • 关闭弹跳似乎并没有改变任何东西。当我到达第三个牢房时,我仍然会听到“哔”声。
  • @jasamer 你能上传这个问题的视频并分享链接吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-02
  • 1970-01-01
  • 2017-01-28
  • 1970-01-01
  • 2020-04-16
  • 2023-03-19
  • 1970-01-01
相关资源
最近更新 更多