Smooth scaling in a UIScrollView

Not too long ago, we were working on an iOS project that involved drawing some custom content that the user can pan and zoom using a UIScrollView.  Because all our drawing was done with CoreGraphics vector-based calls (that is, we're not just blitting any image maps), we thought that it would zoom up smoothly.  Unfortunately, that's not the case; it appears that, under the hood, UIScrollView draws the content to a pixel map, and then just pans and zooms that.  The result is, when the zoom scale is greater than 1.0, the content looks all pixely and ugly.


We searched the interwebs, and found lots of other people who noticed the same problem, but no great solutions.  Many people suggest mucking with the content view's transform in the scrollViewDidEndZooming delegate method; the idea is to reset the actual scale in the content view back to 1, but store a variable that lets you redraw everything smoothly at a larger scale after the user is done scrolling.  Others suggest mucking about with a CATiledLayer, even if you didn't need one before.  Neither of these techniques worked well for us, and besides, we don't really want to to "pop" to a smoother view when the zooming is done; we want it to be smooth all the time.

We finally settled on a different approach, which in my view, is pretty straightforward, and it looks great.  The key insight is that you can, in recent versions of iOS at least, set the initial zoom scale of a UIScrollView to something other than 1.0.  So we just define scale 1.0 to be our maximum zoom, and start out at a smaller scale:

	scroller.contentSize = 	myContentView.bounds.size;
	scroller.maximumZoomScale = 1.0;
	scroller.minimumZoomScale = 0.33;	
	scroller.zoomScale = 0.33;



This lets the user zoom in by a factor of 3 -- but when they do so, they're really just zooming up to full resolution, at which 1 pixel in the UIScrollView's content buffer is 1 pixel on screen.  (And of course, within our content view, we draw everything three times bigger to compensate.)  No need to implement any of the delegate methods except the standard viewForZoomingInScrollView; no redrawing at different scales depending on the zoom.  The image is smooth and beautiful even while zooming.

So the next time you're using a UIScrollView, and you start seeing pixels when you zoom in, perhaps this trick will work as well for you as it does for us.