Zooming to a point in UIScrollView

(Updated March 2015) I’ve rewritten the code for zooming to a CGPoint in a UIScrollView to be even better in a new blog post. Go check it out!

If there’s one piece of functionality that has become basically boilerplate on iOS, it’s the concept of double-tapping a zoomable UIScrollView to quickly zoom in on a given point. When I was writing the code for displaying pages in iComics, I assumed that this would be a really simple thing to do. I mean, surely all you’d need is a UITapGestureRecognizer attached to a UIScrollView that passes the location of any double-taps to the scroll view… right?

Nope. XD

Turns out that although there is a UIScrollView method called ‘zoomToRect‘ (which lets you zoom to a specific CGRect region of a UIScrollView), out-of-the-box, there is no official way to procedurally zoom into a specific CGPoint. This actually surprised me greatly since I would have thought it would be a standard part of UIKit.

In any case, I did a bit of searching around on Google, looking for some code that would let me do this easily. I found a few bits of code here and there, however they were written in such a way that unless the minimum and maximum scales of the scroll view were set up in a specific way (Uh, which in iComics’ case, they weren’t), the zooming wouldn’t work properly at all.

So, cutting to the chase, I decided to just roll my own category for UIScrollView to add that functionality to it. All it does is take a CGPoint (relative to the bounds of the scroll view itself) and a scale, and translates those to a CGRect that can then be passed to UIScrollView’s drawToRect method. :)

Here’s what it looks like:

Looking at it, it should be pretty straightforward to figure out how it works. If you see anything wrong with it, let me know in the comments. As always, feel free to use this code in any of your projects, and let me know if you make anything awesome with it. :)

  • Andre

    Thanks Tim!
    Keep them posts coming!

  • Haha thanks a lot Andre!

    Haha I’ll see what else I can find. XD

  • Cupcake

    Thanks! Very nice post, just what I needed.

  • Very useful, thanks a lot :-)

  • Example

    amazing code dude 

  • Tried it out, but I think the code assumes that the zoomScale is 1.0 when called.  I would like to double the zoomScale on each tap until it gets to maximumZoomScale.  First execution works great.  Second time, the center point is off significantly.

    I’ll post an update once I figure it out.

    • Hi Daniel!

      Thanks for the reply!

      Oh yeah. You might be right. Since my app employs the method of only zooming in when the zoomScale == 1.0, I never tested beyond that.

      In theory, it shouldn’t be too hard to work out. If you do, I’d very much appreciate that update! Thanks! :)


  • Hi! Thanks for the code! I just ported this to Swift for use in my own project—feel free to take it!


  • Rendy Pranata

    Awesome, tried this and works like a charm!

  • A swift version of the code (without the zoomscale not being 1.0 fix) if it helps anyone who was looking for this solution:

    extension UIScrollView {

    func zoomToPoint(zoomPoint: CGPoint, withScale scale: CGFloat, animated: Bool) {
    //Normalize current content size back to content scale of 1.0f
    let contentSize = CGSize(width: (self.contentSize.width / self.zoomScale), height: (self.contentSize.height / self.zoomScale))

    //translate the zoom point to relative to the content rect
    let newZoomPoint = CGPoint(x: (zoomPoint.x / self.bounds.size.width) * contentSize.width, y: (zoomPoint.y / self.bounds.size.height) * contentSize.height)

    //derive the size of the region to zoom to
    let zoomSize = CGSize(width: self.bounds.size.width / scale, height: self.bounds.size.height / scale)

    //offset the zoom rect so the actual zoom point is in the middle of the rectangle
    let zoomRect = CGRect(x: newZoomPoint.x – zoomSize.width / 2.0,
    y: newZoomPoint.y – zoomSize.height / 2.0,
    width: zoomSize.width,
    height: zoomSize.height)

    //apply the resize
    self.zoomToRect(zoomRect, animated: animated)