在我目前正在处理的应用程序中,有一个嵌套的集合视图设置 . 外部集合视图包含可垂直滚动的大单元格,每个单元格包含另一个具有较小单元格的集合视图(子集合视图中的布局不同,这就是为什么有多个单元格) .
在视觉上,一切正常,但我遇到了Voice Over的一个问题:当我到达第一个子集合视图中的最后一个项目时(即外部集合视图的第一个单元格的最后一项),我不能通过滑动选择下一个项目 . 相反,iOS会将声音视为最后一个项目 .
我可以用三指滑动向下滚动,然后选择下一个元素,但这显然不是必需的 . 选择最后一个元素并以相反的顺序返回,按预期工作 .
只有当一个单元格(外部集合视图)最初可见时才会出现问题 . 如果可以看到多个单元格,一切正常 . 但是,我无法更改外部单元格的大小,因为这会完全改变布局 .
我在下面创建了一个示例视图控制器来演示该问题 . 除了单元格的大小之外,项目中的两个集合视图是相同的 . 具有较小单元格的第一个集合视图按预期工作 . 第二个没有(当选择下一个单元格时,iOS会在选择最后一个可见单元格时播放“嘟嘟”声,即使有更多单元格进一步向下) .
所以,我的问题是:
-
如何使第二个集合视图的行为与第一个相同?
-
如何通过水平滑动访问第二个集合视图中的单元格?
到目前为止我尝试的解决方案:
-
一篇SO帖子建议为嵌套集合视图创建包装器视图 . 这似乎没有任何区别 .
-
我试图在集合视图的自定义子类中自己实现UIAccessibilityContainer协议 . 这似乎以奇怪的方式打破滚动 .
-
在随机位置放置"layout changed"通知以查看是否有帮助(它没有)
编辑:演示此问题的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(请注意,我在那里添加了一些描述) .
1 回答
根据我的理解问题,一旦到达内部集合视图中的最后一个单元格,就无法滚动到外部集合视图中的下一个单元格 . 但是三指滑动有效 .
这是因为集合视图上的反弹属性 . 尝试关闭内部集合视图上的bounce属性 .
在上面的代码中,在OuterCell init方法中添加以下代码行 .