Hi Thomas!
Did you add both the code snippets I mentioned?
First the contentInset
let screenWidth = UIScreen.main.bounds.width
lensCollectionView.contentInset = UIEdgeInsets(top: 0, left: screenWidth/2, bottom: 0, right: screenWidth/2)
And then remove this part:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let middleIndexPath = IndexPath(item: lensFiltersImages.count/2, section: 0)
selectCell(for: middleIndexPath, animated: false)
}
And replace it with:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
lensCollectionView.setNeedsLayout()
lensCollectionView.layoutIfNeeded()
let middleIndexPath = IndexPath(item: lensFiltersImages.count/2, section: 0)
selectCell(for: middleIndexPath, animated: false)
}
That should do the trick. There are still some potential edge cases that remain, but unfortunately we don’t have time to cover all of that within a 10-minute video.
One of the edge cases is, for example, when the scroll view can’t determine one specific index path, because the xyPoint
of where the user has scrolled to is smack down in the middle between two cells.
I’m referring to this piece of code:
guard let indexPath = lensCollectionView.indexPathForItem(at: xyPoint) else { return }
When that happens you kind of have to decide where you want the user to go - either left or right. For example, let’s say that if the user is scrolling to the left and the lensCollectionView
can’t determine the indexPath
from the xyPosition
we want to go to the closest left cell, and if they’re scrolling to the right, we want to go to the closest right cell. We could write something like this:
guard let indexPath = lensCollectionView.indexPathForItem(at: xyPoint) else {
let middleX = lensCollectionView.contentSize.width/2
// Scrolling left
if xPosition < middleX {
let xyPoint = CGPoint(x: xOvershotPosition, y: yPosition)
guard let indexPath = lensCollectionView.indexPathForItem(at: xyPoint) else { return }
selectCell(for: indexPath, animated: true)
}
// Scrolling right
else {
let xyPoint = CGPoint(x: xOvershotPosition, y: yPosition)
guard let indexPath = lensCollectionView.indexPathForItem(at: xyPoint) else { return }
selectCell(for: indexPath, animated: true)
}
return
}
This works well, but we’re still left with an edge case of what happens when the user scrolls to the end of the collection view on either end - left and right. We can determine if they’re at either end of the collection view by looking at the xPosition
and the contentSize
of the collection view. When the xPosition <= 0
that means that they’re at the left end. When the xPosition >= collectionView.contentSize.width
that means that they’re at the right end. Knowing all of that, our final implementation can look something like this:
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let bounds = lensCollectionView.bounds
let xPosition = lensCollectionView.contentOffset.x + bounds.size.width/2.0
let yPosition = bounds.size.height/2.0
let xyPoint = CGPoint(x: xPosition, y: yPosition)
guard let indexPath = lensCollectionView.indexPathForItem(at: xyPoint) else {
let middleX = lensCollectionView.contentSize.width/2
// Scrolling left
if xPosition < middleX {
let xOvershotPosition = xPosition - 10
if xOvershotPosition <= 0 || xPosition <= 0 {
let firstIndex = IndexPath(row: 0, section: 0)
selectCell(for: firstIndex, animated: true)
} else {
let xyPoint = CGPoint(x: xOvershotPosition, y: yPosition)
guard let indexPath = lensCollectionView.indexPathForItem(at: xyPoint) else { return }
selectCell(for: indexPath, animated: true)
}
}
// Scrolling right
else {
let xOvershotPosition = xPosition + 10
if xOvershotPosition >= bounds.width || xPosition >= bounds.width {
let lastIndex = IndexPath(row: lensFiltersImages.count - 1, section: 0)
selectCell(for: lastIndex, animated: true)
} else {
let xyPoint = CGPoint(x: xOvershotPosition, y: yPosition)
guard let indexPath = lensCollectionView.indexPathForItem(at: xyPoint) else { return }
selectCell(for: indexPath, animated: true)
}
}
return
}
selectCell(for: indexPath, animated: true)
}
Hope that helped!