A Simpler Magnifying Glass (Loupe) View for the iPhone


I recently needed to create one of those magnifying glasses in an iPhone app that shows you a close-up view of where you're touching. Searching around led me to this article by Sean Christmann, which was really helpful in showing me how to create what I was looking for (Thanks Sean!).

However, once I got familiar with his approach, it seemed like there had to be a simpler and possibly more efficent way to get the same thing. He generates a cached image to get the effect, which takes up some memory, but more importantly, it also prevents the magnifying glass from having live updates (which I needed). In other words, once the magnifier is there, any activity going on beneath it won't be properly shown.

So, I wrote my own. Whereas Sean's magnifier generates an image, does some transforms on it, then shows a masked portion of that static image, mine does some transforms on the context of the magnifier view itself, then renders the view to be magnified directly into the magnifier view. Thus, every time the magnifier is re-drawn, it is rendering the current state of the view, resulting in live updates. Here's the drawRect method for my version of the magnifier:

- (void)drawRect:(CGRect)rect {
    // here we're just doing some transforms on the view we're magnifying,
    // and rendering that view directly into this view,
    // rather than the previous method of copying an image.
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextScaleCTM(context, 1.5, 1.5);
    [self.viewToMagnify.layer renderInContext:context];

In my typical fashion, I'm going to leave out a lot of the other details about how my implementation differs, but I'll be happy to answer any questions in the comments.

Here's a zip of the XCode project containing my Magnifier.

Also, if you'd like to know when I post more article like this, join the Coffeeshopped Newsletter.


Sean's picture

This is much better. I really haven't spent as much time looking into layers as I should. And now knowing you can render a layer into multiple contexts is just that much cooler.

Chadwick Wood's picture

Glad to do my part!

Harvey's picture

Hello Chadwick, Excellent code! I really like your implementation and it is exactly the effect I am looking for, I'm stuck however, I am trying to convert it for with cocos2d. Do you have any experience with that?

I tried also using the newly released "CGImageRef UIGetScreenImage(void);" . I am just having issues trying to convert the UIView stuff to CCDirector stuff.

Thanks for any time you have for my question!!


Chadwick Wood's picture

Hi Harvey,

Unfortunately, I haven't used cocos2d, so I can't help you there. Wish I could.

hm50's picture

I am working on trying to convert it for cocos2d use, I'll post here again when I have it working.

Thanks again, for your help and the class!!

Kelly's picture

Thanks for the article, this is awesome!

Any idea on how to achieve the overlay effect that Apple uses so that it actually looks like a magnifying glass?

Chadwick Wood's picture

Hi Kelly, I think all you need to do to get it to look more like a magnifying glass is use a PNG of a magnifying glass (in a UIImageView), with transparency in the "glass" part, and overlay that on top of the view class I've created. You could probably just add the UIImageView as a subview of my class.

Kelly's picture

Thanks again for the help! I was able to get this to work doing what you suggested (adding a UIImageView as a subview of the Magnifier class). My photoshop skills are pretty poor, but I'd be happy to send you the image I created if you want to add it to your project.

Anonymous's picture

Hi Kelly, Can you share that code somewhere? i tried but could not make it work correctly.

Kelly's picture

Sure, here's the important part in MagnifierView:

- (id)initWithFrame:(CGRect)frame {
    return [self initWithFrame:frame radius:100];

- (id)initWithFrame:(CGRect)frame radius:(int)r {
    radius = r;

    if ((self = [super initWithFrame:CGRectMake(0, 0, radius, radius)])) {
        //Make the layer circular.
        self.layer.cornerRadius = radius / 2;
        self.layer.masksToBounds = YES;

        UIImage* image = [UIImage imageNamed:@"Loupe.png"];

        imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, radius, radius)];
        imageView.image = image;
        [self addSubview:imageView];

    return self;

Let me know if need the image.

Anonymous's picture

Thanks ! it worked for a round loupe image but i wanted to have something like a real-lense with handle? any ideas?

Kelly's picture

I'm thinking you would just use two image views - one for the glass part and one for the handle. I would have to try it to know for sure.

Craig's picture

Thanks for the quickstart getting this functionality (which should be built into the OS) implemented. A couple of notes:

setTouchPoint assumes the coordinate systems of the magnified view and the magnifier's superview have the same origin. Add this line to setTouchPoint to fix:

// pt is in the coordinate space of the magnified view, which may be 
// different than the coordinate system of the magnifier's superview. 
// Transform it to superview coordinates.

touchPoint = [viewToMagnify convertPoint:pt toView:self.superview];

Similarly, in drawRect:

// touchPoint is in OUR coordinate space. Transform to the magnified view's
// space to magnify.

CGPoint magnifiedPoint = [viewToMagnify convertPoint:touchPoint fromView:self.superview];
David's picture

Extremely nice and helpful. Anyone with any idea of how to keep the magnifier above (i.e., overlapping and hiding) the status bar like it is in the Apple Notes notepad application?

p.s. The view I am magnifying is contained in a UIScrollView so I needed to do the coordinate space translation like Craig says above plus I had to make sure I initialized the center point after adding my "loop" to the superview.

Matt K's picture

Hey guys, love the code and am surprised I haven't found anything else even similar to what it accomplishes.

My current project requires me to have a static, permanent magnifier above a UIPickerView's selector. I've already manipulated your code to get something similar to this, however I've met with a few snags:

1) I'm handling everything inside of a viewcontroller that imports Magnifier.h (no TouchReader). Because of this, my view uses the default UIView class. The issue I'm having is when I try to add loop to my view's superview (which I would think would be the viewcontroller) [self.view.superview addsubview:loop]. This runs, but doesn't show loop. When I just add it to the view, it appears but magnifies itself as the original code warned. What's more confusing is that the original source code seems to also be referencing a superview on a view that appears to already be at the top of the hierarchy. Any ideas why and how I could fix this?

2) My second problem is something that may not be possible to fix. Loop refreshes pretty well when dragged around or after interacting with objects but it's during interaction that it freezes up. I have it set on a timer of .01 so that it is constantly refreshing. For whatever reason, when I interact with the wheels on my picker all updating stops until I let it sit on a value, then it continues and even show's the slight animation of the value sliding into place. I know the constant timer loop is most likely a huge drain on the processor but I'm still curious why the process pauses. Any superior methods are also appreciated.

Thanks in advance and again for the code!

Joe Amos's picture

I am working on an app that requires an magnifying glass, do you still have that image you created? If so I would really appreciate it if you could forward it to me.

Moon's picture

Did you ever try this out? I played around with your code some but I am a noob, and the pesky "MasksToBounds" always seems to get into the way...

Moon's picture

Oops, context: the above was in respones to Kelly's post:

Kelly on May 6, 2011:

I'm thinking you would just use two image views - one for the glass part and one for the handle. I would have to try it to know for sure.

Adam Howitt's picture

Great code! Struggling with device orientations though. The updated code to relocate the touch in the correct coordinates works well but the renderInContext function when I switch to landscape shows the layer I want but with a 90 degree rotation in either direction or, if the phone is upside down, with a 180 degree rotation. Is there a way to rotate the layer as I render it into the context?

Adam Hellewell's picture

Great job! I am trying to use what you have an apply it to the photoscroller that was shown at WWDC a couple of years ago. However, I am getting a black image in the magnifying glass. I'm guessing it is because I am not applying the magnifying glass to the correct view. Any ideas on how to apply the magnifying glass to a view with several subviews?

Melisa's picture

Hi, this is just what I've been looking for the past few days and I would like to implement this on an existing app I created but I don't know how to limit the area that can be magnified (like a photo or a map). Can you help me out? Also, I'm having trouble locating the magnifier, it displays the background image in a different area...

Thanks in advance!

dat's picture

Thanks a lot

Sara's picture

Thanks a lot!!

Ishhhh's picture

Heyyy thats a Great code and it really helped :)))))) Thanks :) (y)

Vakul Saini's picture

Great sample code ..... Saved my day :) Thanks @Chadwick Wood

High's picture

Great code! I have noticed performance issues though when dealing with a full resolution image from the iPhone 4S/5. Do you have a suggestion on how to address the issue? I've looked at how the magnifier works with PDF files on the phone. It takes it a second or so, but it looks like it does some sort of caching/compression of the file.

iHungry's picture

Cool...... Really nice idea.