UIScrollView Custom Paging

Viewed 15666

My question has to do with a custom form of paging which I am trying to do with a scroller, and this is easier to visualise if you first consider the type of scroll view implemented in a slot machine.

So say my UIScrollView has a width of 100 pixels. Assume it contains 3 inner views, each with a width of 30 pixels, such that they are separated by a width of 3 pixels. The type of paging which I would like to achieve, is such that each page is one of my views (30 pixels), and not the whole width of the scroll view.

I know that usually, if the view takes up the whole width of the scroll view, and paging is enabled then everything works. However, in my custom paging, I also want surrounding views in the scroll view to be visible as well.

How would I do this?

7 Answers

I've been struggling to overcome this issue, and I found an almost perfect solution which is to ideal with and paging width you want.

I'd set scrollView.isPaging to false (meanwhile, it's false by default) from UIScrollView and set its delegate to UIScrollViewDelegate.

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

    // Stop scrollView sliding:
    targetContentOffset.pointee = scrollView.contentOffset

    if scrollView == scrollView {
        let maxIndex = slides.count - 1
        let targetX: CGFloat = scrollView.contentOffset.x + velocity.x * 60.0
        var targetIndex = Int(round(Double(targetX / (pageWidth + spacingWidth))))
        var additionalWidth: CGFloat = 0
        var isOverScrolled = false

        if targetIndex <= 0 {
            targetIndex = 0
        } else {
            // in case you want to make page to center of View
            // by substract width with this additionalWidth
            additionalWidth = 20
        }

        if targetIndex > maxIndex {
            targetIndex = maxIndex
            isOverScrolled = true
        }

        let velocityX = velocity.x
        var newOffset = CGPoint(x: (CGFloat(targetIndex) * (self.pageWidth + self.spacingWidth)) - additionalWidth, y: 0)
        if velocityX == 0 {
            // when velocityX is 0, the jumping animation will occured
            // if we don't set targetContentOffset.pointee to new offset
            if !isOverScrolled &&  targetIndex == maxIndex {
                newOffset.x = scrollView.contentSize.width - scrollView.frame.width
            }
            targetContentOffset.pointee = newOffset
        }

        // Damping equal 1 => no oscillations => decay animation:
        UIView.animate(
            withDuration: 0.3, delay: 0,
            usingSpringWithDamping: 1,
            initialSpringVelocity: velocityX,
            options: .allowUserInteraction,
            animations: {
                scrollView.contentOffset = newOffset
                scrollView.layoutIfNeeded()
        }, completion: nil)
    }
}

slides contains all page views that you have inserted to UIScrollView.

Related