Over the past few months, I've been working on an iOS application laden with scroll views. Because of the fluid and interactive design, I needed to make sure multiple instances of
UIScrollView and its subclass,
UICollectionView, worked together seamlessly.
Often times, as one view moved, one or more others also needed to move. This can be facilitated by using
scrollViewDidScroll:, but you have to be careful when updating subsequent scroll views. Why? Well, the normal method for updating a scroll view to a particular location
setContentOffset:animated: also invokes
scrollViewDidScroll:. You can see why this might be a problem...
Our friends over at objc.io have given a thorough and excellent overview of how
UIScrollView works under the hood (I highly recommend the read). Long story short,
contentOffset and consequently,
setContentOffset:animated:, are made up! They don't actually exist on their own—they're simply wrappers around the
bounds of a scroll view.
setContentOffset:animated: is actually just updating
bounds.origin to the CGPoint provided and optionally animating this update. It's also invoking that delegate method that would normally be causing us problems. So how do we get around this? Simply update the
bounds.origin directly instead of using
setContentOffset:animated: to avoid invoking
Another important property of UIScrollView is
contentInset. By using this property, we're able to add (and also remove, should you need to) blank space to our scroll view on any of its sides.
This can be useful when the onscreen keyboard displays over an input form, for example. Instead of mucking with the frame or with auto layout constraints, simple update the
contentInset: when the keyboard shows, add the keyboard's height to the bottom; when the keyboard hides, subtract its height from the bottom.
Besides the above example, I also used this property, in conjunction with a clear background, to display custom hero graphics in a recent application, allowing the content to scroll on top of them.
I put together a super simple app to demonstrate visually (and in code) these concepts, which will hopefully clarify anything I missed. It has a horizontal scroll view containing an image from a recent trip to Death Valley, textual representation of
bounds.origin (you'll see they're the same), and a slider for modifying
Check out the code on Github here.
As always, feel free to reach out on Twitter @jonathonstaff if you have any questions/feedback.
Recommended reading: Understanding Scroll Views and Apple's Documentation on UIScrollView.