How to think about UIScrollView.contentInset

Up until three months ago, my time at the Omni Group had been spent programming solely for the Mac—I hadn’t written any iOS code professionally, and I’d only dabbled the slightest bit on the side.

That all changed when iOS 7 was announced, and I’ve now spent a solid three months as an iOS developer. For the most part, it was an easy transition; I’d picked up quite a bit of iOS knowledge peripherally, and I learned a lot more very quickly through hands-on experience. But one thing bedeviled me: UIScrollView.

UIScrollView is significantly different from its Macintosh counterpart. While both views perform their actual scrolling by translating their bounds.origin, the way one defines the scrollable region is completely different on both platforms. On OS X, the scroll view (actually its clip view) has a single subview called the documentView whose frame.size defines the scrollable region. On iOS, however, the size of the scrollable region is defined by two properties: contentSize and contentInset.

contentSize is simple enough to understand. And if you’re using Auto Layout, you don’t even need to set it yourself. And indeed you must not; it’s computed from the constraints that relate the scroll view to its subviews.

contentInset is trickier. Nothing like it exists on the Mac. Experimentally, it appears to be a way to extend the contentSize, perhaps exposed as a separate property so as to divide responsibility between the scroll view and its view controller. And indeed, we have plenty of code that treats that property as an extension of contentSize.

But I now think that’s semantically wrong. Rather, the correct meaning of contentInset is “the space into the visible frame of the scroll view which other UI elements protrude.” Apple’s documentation hints at this explanation, but it leads by example rather than by definition. Their explanation starts by stating the desired result, and then points you at the contentInset property and says “use this to add padding.” It doesn’t explain the subtlety of what is being padded.

So here’s the short version: contentInset doesn’t inset the content within the scrollable area—it insets the viewport within the scrollview’s frame. It extends the scrollable area as a side effect so that scrolling to the extremes produces the correct visual result.