iOS: Scalable, Scrollable Views

I've got a Mac project I'm working on that required a scalable viewport into another view.  Because the viewport could be a scaled version of the target view, it also needs to be scrollable.  This sort of pattern is seen a lot in editing applications and web browsers.  Specifically, I was looking to mimic the iPhone Simulator app.  It took me about 10 hours of wrangling cocoa to get it to do what I wanted.  I tried writing a custom NSClipView among other tactics, but what I found to work in the end was pretty simple.  This technique should transfer to iOS readily.

To scale the view you're inspecting, you'll likely use NSView's scaleUnitSquareToSize: selector.  This will render the view's contents using Quartz scaling algorithms.  However, it will not change the frame/bounds of the view.  This is where the crux of the problem lies - the scroll extents of the scroll view would not change.  When scaled up, the scroll view would not scroll enough of the view to see all of it.  When scaled down, the scroll view would scroll too far and show emptiness on the sides of the document.

To work around this, we will create a new document view that advertises the correct frame to the scroll view.  It will host the true document view as a subview, without clipping it and without autoresize enabled.  It will monitor the document view's frame and adjust accordingly.  It will also need to know the scale of the document view, and the easiest way to handle that is to have this new host view control the scale of the document.  Here's all the code you need:

https://gist.github.com/715903/e11a0afe4245fa697e5660d4fc887eae08275bec

Once you have this code, you can call setDocumentView: on any scroll view with a HostView.  When you need to change the scale, call setScale: (or use the property accessor) on the HostView.  The scroll view will adjust its scroll bars accordingly.

Note, however, that the scroll view's frame will not change - the scroll view's size will be the same, but the scroll bars will reflect the correct amount of data that is visible.  If you want the scroll view to adjust its size correctly to fit the document, you will need to add some more monitoring to the document's frame size and adjust accordingly outside of the scroll view itself.

~s