Search code examples
iosswiftuicollectionviewcore-animation

How to animate when swiping through collection view


I have a collectionView inside of a ViewController. When I swipe, it swipes to another Collection View Cell which is the height and width of the view.frame

I want to have an animation that starts whenever I start swiping, to then finish whenever the collection view locks into the centre of a cell just like the gif below. I don't have a label or textview in my code but could you point me in the right direction on how I would do this? Here's my relevent code:

class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {

lazy var collectionView: UICollectionView = {
    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = .horizontal
    layout.minimumLineSpacing = 0
    let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
    cv.backgroundColor = .white
    cv.dataSource = self
    cv.delegate = self
    cv.isPagingEnabled = true
    cv.showsHorizontalScrollIndicator = false
    return cv
}()

let cellId = "cellId"
let loginCellId = "loginCellId"

let pages: [Page] = {
    let firstPage = Page(imageName: "introduction_1")
    let secondPage = Page(imageName: "introduction_2")
    let thirdPage = Page(imageName: "introduction_3")
    let fourthPage = Page(imageName: "introduction_4")
    return [firstPage, secondPage, thirdPage, fourthPage]
}()

lazy var  pageControl: UIPageControl = {
    let pc = UIPageControl()
    pc.pageIndicatorTintColor = .lightGray
    pc.currentPageIndicatorTintColor = .darkGray
    pc.numberOfPages = self.pages.count + 1
    return pc
}()

override func viewDidLoad() {
    super.viewDidLoad()

    view.addSubview(collectionView)
    view.addSubview(pageControl)

    _ = pageControl.anchor(nil, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 40)

    collectionView.anchorToTop(view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor)

    registerCells()
}

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {

    let pageNumber = Int(targetContentOffset.pointee.x / view.frame.width)
    pageControl.currentPage = pageNumber
}

fileprivate func registerCells() {
    collectionView.register(PageCell.self, forCellWithReuseIdentifier: cellId)
    collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: loginCellId)

}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return pages.count + 1
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    if indexPath.item == pages.count {
        let loginCell = collectionView.dequeueReusableCell(withReuseIdentifier: loginCellId, for: indexPath)
        return loginCell
    }

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! PageCell

    let page = pages[indexPath.item]
    cell.page = page

    return cell
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: view.frame.width, height: view.frame.height)
}

}

class PageCell: UICollectionViewCell {

var page: Page? {
    didSet {
        guard let page = page else {
            return
        }
        imageView.image = UIImage(named: page.imageName)
    }
}

override init(frame: CGRect) {
    super.init(frame: frame)

    setupViews()
}

let imageView: UIImageView = {
    let iv = UIImageView()
    iv.contentMode = .scaleAspectFill
    iv.backgroundColor = .yellow
    iv.clipsToBounds = true
    return iv
}()

func setupViews() {

    addSubview(imageView)

    imageView.anchorToTop(topAnchor, left: leftAnchor, bottom: bottomAnchor, right: rightAnchor)
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

}

enter image description here


Solution

  • From my standpoint, in your case it is better to use UIPageViewController instead of UICollectionView. It has a whole bunch of features for you to implement the UI you've shown above. There is a good tutorial on this topic - https://www.veasoftware.com/posts/uipageviewcontroller-in-swift-xcode-62-ios-82-tutorial?rq=page