Source for FastPagingFlowLayout.

import UIKit

/// FastPagingEffect를 가지는 FlowLayout. class FastPagingFlowLayout: UICollectionViewFlowLayout {

override func prepare() {
    super.prepare()
    collectionView?.decelerationRate = UIScrollViewDecelerationRateFast
}

/*
 User의 scroll이 멈추는 순간 화면의 midX를 기점으로 item을 중앙정렬하여
 마치 paging이 되는것처럼 보이도록 contentOffset을 조정한다.
 */
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
    guard let collectionView = collectionView else {return proposedContentOffset}
    let viewSize = collectionView.bounds.size
    let proposedRect = CGRect(x: proposedContentOffset.x, y: 0, width: viewSize.width, height: viewSize.height)

    // 화면상에 보여지는 item들의 layoutAttributes를 가져온다.
    guard let layoutAttribute = layoutAttributesForElements(in: proposedRect) else {
        return proposedContentOffset
    }

    var candidateAttribute: UICollectionViewLayoutAttributes?
    let proposedContentOffsetMidX = proposedContentOffset.x + viewSize.width / 2
    // scroll된 contentOffset을 더하여 계산된 보여지는 화면상의 midX값.

    for attribute in layoutAttribute where attribute.representedElementCategory == .cell {
        if candidateAttribute == nil {
            candidateAttribute = attribute
            continue
        }
        // 화면상의 보여지는 item들의 layoutAttribute중에서 최대한 midX값에 근접한 layoutAttribute를 찾는다.
        let attributeValue = fabs(attribute.center.x - proposedContentOffsetMidX)
        let cadidateValue = fabs(candidateAttribute!.center.x - proposedContentOffsetMidX)
        if attributeValue < cadidateValue {candidateAttribute = attribute}
    }

    guard candidateAttribute != nil else {return proposedContentOffset}
    var newOffsetX = candidateAttribute!.center.x - viewSize.width / 2
    let offset = newOffsetX - collectionView.contentOffset.x

    /*
     User가 가만히 있다가 action을 중단했는지 아니면 swipe action을 취했는지 판단하여
     해당 swipe 방향에 따라 이전 또는 다음 item의 위치를 추가로 계산해준다. (쓩~ 넘어갈 수 있도록 하는,)
     */
    if (velocity.x < 0 && offset > 0) || (velocity.x > 0 && offset < 0) {
        let pageWidth = viewSize.width + minimumLineSpacing
        newOffsetX += (velocity.x > 0) ? pageWidth : -pageWidth
    }

    return CGPoint(x: newOffsetX, y: proposedContentOffset.y)
}

}