Sarreph Sarreph - 6 months ago 20
Swift Question

Jumpiness in UIScrollView (when removing top 'page')

I'm building a prototype of a custom, paged

UIScrollView
whose core functionality is to remove the current/topmost 'page' as soon as it passes the top view boundary (i.e. goes completely out of view). This has been working fine with rather primitive code in the scrollView's delegate, but continuous swiping from the second 'page' onwards causes a glitch whereby the scrollView jumps to the next page very quickly. This continues until the scrollView is moved in the opposite direction.

I am using playing card images in my image array as the pages, and since the core user functionality is to be quickly swiping through these card pages, it is very poor UX to have a glitchy/fast response.

For example please see the video below:

(approx. 10 secs - excuse the replaying)
enter image description here

My code is:

func scrollViewDidScroll(scrollView: UIScrollView) {

if (scrollView.contentOffset.y >= scrollView.frame.height) {
print("CATCH at \(scrollView.contentOffset.y)")

// Handle 'cards' UIImageView array directly
self.cards.first?.removeFromSuperview()
self.cards.removeFirst()
for cardImage in self.cards {
cardImage.frame = CGRectOffset(cardImage.frame, 0, -cardImage.frame.height)
}

// Resize the scrollView's contentView and coordinates
scrollView.contentSize = CGSizeMake(scrollView.frame.width, scrollView.contentSize.height - scrollView.frame.height)
scrollView.setContentOffset(CGPointMake(0, 0), animated: false)

print("new content offset: \(scrollView.contentOffset.y)")
}
}


In the above code, when the view starts to 'glitch' (i.e. scroll very fast), the 'CATCH' value of
contentOffset.y
exceeds the view height — and when it is 'smooth' the 'CATCH' value is exactly the page height (what we would expect from a normal pagination animation); therefore, I can only assume it is catching the view too late as it is going too quickly (?)

The glitching is stopped by moving the scrollView in the opposite direction a little first, suggesting that something about the scrollView's animation or velocity is reset when doing so.

I've tried many different methods in the
scrollViewDidEndDecelerating
delegate, such as resetting the scrollView's
panGestureRecognizer
and
scrollEnabled
, to no avail.

Appreciate pointers here!

Answer

After experimenting with UIScrollViewDelegate's various delegate functions, I've discovered that manipulating scrollViewDidScroll at a point where the scrollView naturally stops (such as the end of the next page in a paged scrollView) bypasses scrollViewDidEndDecelerating in some circumstances (such as this one), and causes it to mis-fire once scrolling starts again, which is what was causing the page-jumping above.

The solution was to move my code to scrollViewDidEndDecelerating and to handle the 'live' scroll event edits only in scrollViewDidScroll.

Comments