【发布时间】: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