'collectionView Animation on SwipUP?
I want to animate a collectionView on swipe on the basis of content offset. it's like a page controller but shows only one swipe. I have attached a video because I know the explanation is not good.
you can download the video from there.
Solution 1:[1]
There can be several ways to do what you want, here is one way:
I am setting up a UIImageView along with an overlay UIView which is pinned to the main view's leading, trailing, top and bottom anchors.
My aim is to swipe up a collection view like your example and then change the color of the overlay view based on the cell tapped in the collection view.
Here are some vars and the initial set up:
class SwipeCollectionView: UIViewController
{
private var collectionView: UICollectionView!
private let imageView = UIImageView()
private let overlayView = UIView()
// Collection view data source
private let colors: [UIColor] = [.red,
.systemBlue,
.orange,
.systemTeal,
.purple,
.systemYellow]
// Store the collection view's bottom anchor which is used
// to animate the collection view
private var cvBottomAnchor: NSLayoutConstraint?
// Use this flag to disable swipe actions when carousel is showing
private var isCarouselShowing = false
// Use this to check if we are swiping up
private var previousSwipeLocation: CGPoint?
// Random width and height, change as you wish
private let cellWidth: CGFloat = 100
private let collectionViewHeight: CGFloat = 185
private let reuseIdentifier = "cell"
override func viewDidLoad()
{
super.viewDidLoad()
configureNavigationBar()
configureOverlayView()
configureCollectionView()
}
private func configureNavigationBar()
{
title = "Swipe CV"
let appearance = UINavigationBarAppearance()
// Color of the nav bar background
appearance.backgroundColor = .white // primary black for you
navigationController?.navigationBar.standardAppearance = appearance
navigationController?.navigationBar.scrollEdgeAppearance = appearance
}
Now once some basic set up is done, here is how the image and the overlay view was set up. Nothing fancy happens here but pay attention to the gesture recognizer added to the overlay view
private func configureOverlayView()
{
imageView.image = UIImage(named: "dog")
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFill
overlayView.backgroundColor = colors.first!.withAlphaComponent(0.5)
overlayView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(imageView)
view.addSubview(overlayView)
// Auto layout pinning the image view and overlay view
// to the main container view
view.addConstraints([
imageView.leadingAnchor
.constraint(equalTo: view.leadingAnchor),
imageView.topAnchor
.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
imageView.trailingAnchor
.constraint(equalTo: view.trailingAnchor),
imageView.bottomAnchor
.constraint(equalTo: view.bottomAnchor),
overlayView.leadingAnchor
.constraint(equalTo: view.leadingAnchor),
overlayView.topAnchor
.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
overlayView.trailingAnchor
.constraint(equalTo: view.trailingAnchor),
overlayView.bottomAnchor
.constraint(equalTo: view.bottomAnchor)
])
// We will observe a swipe gesture to check if it is a swipe
// upwards and then react accordingly
let swipeGesture = UIPanGestureRecognizer(target: self,
action: #selector(didSwipe(_:)))
overlayView.addGestureRecognizer(swipeGesture)
}
Now once that is done, we need to create a horizontal scrolling uicollectionview that is positioned off screen which can be animated in when we swipe up, here is how this is done
private func configureCollectionView()
{
collectionView = UICollectionView(frame: .zero,
collectionViewLayout: createLayout())
collectionView.backgroundColor = .clear
collectionView.register(UICollectionViewCell.self,
forCellWithReuseIdentifier: reuseIdentifier)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.showsHorizontalScrollIndicator = false
// Add some padding for the content on the left
collectionView.contentInset = UIEdgeInsets(top: 0,
left: 15,
bottom: 0,
right: 0)
collectionView.dataSource = self
collectionView.delegate = self
overlayView.addSubview(collectionView)
// Collection View should start below the screen
// We need to persist with this constraint so we can change it later
let bottomAnchor = overlayView.safeAreaLayoutGuide.bottomAnchor
cvBottomAnchor
= collectionView.bottomAnchor.constraint(equalTo: bottomAnchor,
constant: collectionViewHeight)
// Collection View starts as hidden and will be animated in swipe up
collectionView.alpha = 0.0
// Add collection view constraints
overlayView.addConstraints([
collectionView.leadingAnchor.constraint(equalTo: overlayView.leadingAnchor),
cvBottomAnchor!,
collectionView.trailingAnchor.constraint(equalTo: overlayView.trailingAnchor),
collectionView.heightAnchor.constraint(equalToConstant: collectionViewHeight)
])
}
private func createLayout() -> UICollectionViewFlowLayout
{
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.itemSize = CGSize(width: cellWidth, height: collectionViewHeight)
layout.minimumInteritemSpacing = 20
return layout
}
The code up to this point should give you something like this:
You still do not see the collection view and for that, implement the didSwipe action of the pan gesture
@objc
private func didSwipe(_ gesture: UIGestureRecognizer)
{
if !isCarouselShowing
{
let currentSwipeLocation = gesture.location(in: view)
if gesture.state == .began
{
// record the swipe location when we start the pan gesture
previousSwipeLocation = currentSwipeLocation
}
// On swipe continuation, verify the swipe is in the upward direction
if gesture.state == .changed,
let previousSwipeLocation = previousSwipeLocation,
currentSwipeLocation.y < previousSwipeLocation.y
{
isCarouselShowing = true
revealCollectionView()
}
}
}
// Animate the y position of the collection view and the alpha
private func revealCollectionView()
{
// We need to set the top constraint (y position)
// to be somewhere above the screen plus some padding
cvBottomAnchor?.constant = 0 - 75
UIView.animate(withDuration: 0.25) { [weak self] in
// animate change in constraints
self?.overlayView.layoutIfNeeded()
// reveal the collection view
self?.collectionView.alpha = 1.0
} completion: { (finished) in
// do something
}
}
Finally, just for completeness, here is the collection view data source and delegate:
extension SwipeCollectionView: UICollectionViewDataSource
{
func collectionView(_ collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int
{
return colors.count
}
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell
= collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier,
for: indexPath)
cell.layer.cornerRadius = 20
cell.clipsToBounds = true
cell.contentView.backgroundColor = colors[indexPath.item]
return cell
}
}
extension SwipeCollectionView: UICollectionViewDelegate
{
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath)
{
overlayView.backgroundColor
= colors[indexPath.item].withAlphaComponent(0.5)
}
}
Now running this should give you this experience when you swipe up:
I believe this should be enough to get you started
Update
The full source code of the example is available on a gist here
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |


