20

I would like be able to create a movable magnifier (like the one you have when you copy and paste) in a custom view, for zooming a part of my view.

I have no idea on how to start, do you have any idea?

Thanks in advance for your help :)

AP.
  • 5,205
  • 7
  • 50
  • 94

3 Answers3

16

We do this in Crosswords. In your drawRect method, mask off a circle (using a monochrome bitmap containing the 'mask' of your magnifying glass) and draw your subject view in there with a 2x scale transform. Then draw a magnifying glass image over that and you're done.

- (void) drawRect: (CGRect) rect {
    CGContextRef    context = UIGraphicsGetCurrentContext();
    CGRect          bounds = self.bounds;
    CGImageRef      mask = [UIImage imageNamed: @"loupeMask"].CGImage;
    UIImage         *glass = [UIImage imageNamed: @"loupeImage"];

    CGContextSaveGState(context);
    CGContextClipToMask(context, bounds, mask);
    CGContextFillRect(context, bounds);
    CGContextScaleCTM(context, 2.0, 2.0);

    //draw your subject view here

    CGContextRestoreGState(context);

    [glass drawInRect: bounds];
}
Ben Gottlieb
  • 85,404
  • 22
  • 176
  • 172
  • Sounds really interesting. I will just need to add an overlay to try to mimic the reflect. I am going to test it. Thanks a lot! – AP. Jan 09 '10 at 13:21
  • The code doesn't support a shadow on unscaled area! How to fix this? – Dmitry Nov 11 '12 at 17:13
  • Link to the full code (shadow isn't supported because of the code above isn't fully correct): http://stackoverflow.com/questions/13330975/how-to-add-a-magnifier-to-custom-control/13333807#13333807 – Dmitry Nov 11 '12 at 18:02
  • Thank you , have you any source code ? or sample project ? – iOS.Lover Aug 30 '15 at 15:58
4

There is a complete example over here. There is a minor error in the downloaded project but otherwise it works great and does exactly what you need.

droussel
  • 1,322
  • 1
  • 11
  • 17
  • Can you pull out the relevant bits into the answer? It looks like the link still works, but there's no guarantee as to how long that'll remain true. – Dennis Meng May 31 '15 at 07:26
2

I use this code in Swift 3 :

class MagnifyingGlassView: UIView {

    var zoom: CGFloat = 2 {
        didSet {
            setNeedsDisplay()
        }
    }

    weak var readView: UIView?

    // MARK: - UIVIew

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupView()
    }

    override func draw(_ rect: CGRect) {
        guard let readView = readView else { return }
        let magnifiedBounds = magnifyBounds(of: readView, zoom: zoom)
        readView.drawHierarchy(in: magnifiedBounds, afterScreenUpdates: false)
    }

    // MARK: - Private

    private func setupView() {
        isOpaque = false
        backgroundColor = UIColor.clear
    }

    private func magnifyBounds(of view: UIView, zoom: CGFloat) -> CGRect {
        let transform = CGAffineTransform(scaleX: zoom, y: zoom)
        var bounds = view.bounds.applying(transform)
        bounds.center = view.bounds.center
        return view.convert(bounds, to: self)
    }
}

extension CGRect {
    var center: CGPoint {
        get {
            return CGPoint(x: origin.x + width / 2, y: origin.y + height / 2)
        }
        set {
            origin.x = newValue.x - width / 2
            origin.y = newValue.y - height / 2
        }
    }
}

You need to call setNeedsDisplay in scrollViewDidScroll: if your read view is a scrollView.

GaétanZ
  • 4,870
  • 1
  • 23
  • 30