How to create cells that peek on the sides like iOS 11 App Store
Collection view scrolling and paging have always been a mystery to me. It was until recently we had a requirement for a project where there’s a collection view that shows a part of the previous and next items. So it was time to dig deeper to implement this feature.
I finally decided to implement my own logic and create a pod out of it so it can be easily integrated into projects.
The feature is available here:
The Readme file contains all the necessary information to make it working. For convenience, here’s an example:
After installing the pod and wiring the collection view outlet to the storyboard, here’s the result:
If you’re interested in knowing the inner workings of the MSPeekCollectionViewDelegateImplementation
, continue to the next section.
How does it work?
This section will cover the main functionality of the peeking delegate implementation. (Not all code is shown here but everything is there in the Github repository)
We will not rely on the already existing paging behavior in the collection view, we will implement our own logic. So the Paging Enabled
checkbox will be unchecked.
The Layout:
Here’s a diagram to show the different components of the view:
You can set any value for the cell spacing by using the delegate function:
It’s important to note that, for the feature to work, the cell should be centered in the view. So to do that, we need to set the left and right insets of the collection view to match the peek width and the cell spacing as shown in the figure below.
We can do this using the delegate function:
Since the cell will occupy the remaining space, we can set the cell’s item size as shown in the delegate function below:
Since there’s two cells peeking from the sides and there’s two spaces between the cells from the left and right itemWidth can be calculated using this equation:
let itemWidth = collectionView.frame.size.width - 2 * (cellSpacing + cellPeekWidth)
The max
function is used just to prevent negative values if the collection view’s width is less than the peek + spacing.
We’ll also set the minimum inter-item spacing to 0 just to be on the safe side:
The Logic:
We will introduce a new parameter called scrollThreshold
. This will determine how much scrolling is needed to snap to the adjacent cell.
We will calculate the distance scrolled by saving the scroll offset when the user starts dragging using:
Here’s the main part. We can implement the logic using the delegate function scrollViewWillEndDragging
.
Let’s break this down into several steps:
- We get the destination where the scroll view‘s dragging will stop from the
targetContentOffset
pointer. The pointer points to the value where the scroll view will stop. Changing this value will change where the scroll view will stop, and it automatically animates it without any extra work. - Calculate the total distance for the scroll.
- Check if the scroll’s magnitude is greater than the
scrollThreshold
and create a coefficient that has one of 3 values (-1, 0, 1). This will be added to the current index. - Get the current index by dividing the offset over the item width
- Add the coefficient retrieved in step 3 to the current index.
- Get the adjacent item scroll offset by adding the item width to the cell spacing first, and then multiplying it by the new adjacent item index retrieved in step 5
- Set the
targetContentOffset
pointee to the new value, which will scroll the collection view to that offset.
Note: Make sure you set the deceleration rate to fast for the collection view or the animation would be slow:
collectionView.decelerationRate = UIScrollViewDecelerationRateFast
Thank you for checking out this tutorial. The repository is still in it’s early stages and new features are planned to be implemented in the near future. Anyone is welcome to contribute to the project and add issues.
Don’t forget to star and share the repo if you found it useful.