Reputation: 1099
In the App that I am currently working on, there is a nested collection view setup. The outer collection view contains large cells that are vertically scrollable, and each cell contains another collection view with smaller cells (the layout in the sub-collection-views differs, that's why there are multiple ones).
Visually, everything works fine, but I came across an issue with Voice Over: When I reach the last item in the first child-collection view (i.e., the last item of the first cell of the outer collection view), I can't select the next item by swiping. Instead, iOS makes the sound as if the last item had been reached.
I can three-finger swipe to scroll down, and then select the next element, but this should obviously not be necessary. Selecting the last element and going back up in reverse order works as intended.
The problem only seems to occur when only one cell (of the outer collection view) is visible initially. If multiple cells are visible, everything works. However, I cannot change the sizes of the outer cells, because that would completely change the layout.
I created a sample view controller below that demonstrates the issue. The two collection views in the project are the same, except for the sizes of the cells. The first collection view with the smaller cells works as expected. The second one does not (when swiping to select the next cell, iOS plays the "beep" sound when the last visible cell was selected, even though there are more cells further down).
So, my question is:
Solutions I have attempted so far:
Edit: Full code of a ViewController that demonstrates the issue:
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")
}
}
Edit: Here is a video that shows the issue: https://vimeo.com/229249955 (Note that I've added a little bit of description there).
Upvotes: 7
Views: 1467
Reputation: 524
From what i understood the problem is you are not able to scroll to the next cell in outer collection view once you have reached the last cell in inner collection view. But however a three finger swipe works.
This is because of the bounce property on collection view. Try turning off the bounce property on the inner collection view.
In the above code, add the following line of code in the OuterCell init method.
innerCollectionView.bounces = false
Upvotes: 2