How would you make a View that magnifies the View(s) beneath it?

I need a magnifying glass function for one of my SwiftUI Views, but can't find a way to implement it as needed.

I found a Youtube video where the author renders the view twice, overlaying the second over the first, then scaling and masking it to create the illusion of magnification, but this is expensive and doesn't work in many cases where more complex views are presented (e.g. a LazyVGrid).

I've also explored continually capturing partial screenshots and scaling them up to create the illusion of magnification, but there's no straightforward way to achieve this with SwiftUI without getting into the messiness of UIViewRepresentables.

Any help would be greatly appreciated

You could use the MagnifyGesture + scaleEffect to magnify and scale the view up and down. Is this something you've looked into?

@DTS Engineer Thank you for your response. I'm trying to magnify a SpriteView within a SwiftUI view where the user's finger is. The SpriteView itself has a pinch gesture for zooming in, but on top of that I need to offer greater gesture precision via a magnifying glass.

MagnifyGesture + scaleEffect therefore wouldn't help.

I've also tried implementing an UIView magnifying glass within the SKScene but it just shows crosshairs.

https://github.com/niczyja/MagnifyingGlass-Swift


import UIKit
import SwiftUI

public class MagnifyingGlassView: UIView {
    public weak var magnifiedView: UIView? = nil {
        didSet {
            removeFromSuperview()
            magnifiedView?.addSubview(self)
        }
    }
    
    public var magnifiedPoint: CGPoint = .zero {
        didSet {
            center = .init(x: magnifiedPoint.x + offset.x, y: magnifiedPoint.y + offset.y)
        }
    }
    
    public var offset: CGPoint = .zero
    
    public var radius: CGFloat = 50 {
        didSet {
            frame = .init(origin: frame.origin, size: .init(width: radius * 2, height: radius * 2))
            layer.cornerRadius = radius
            crosshair.path = crosshairPath(for: radius)
        }
    }
    
    public var scale: CGFloat = 2
    
    public var borderColor: UIColor = .lightGray {
        didSet {
            layer.borderColor = borderColor.cgColor
        }
    }
    
    public var borderWidth: CGFloat = 3 {
        didSet {
            layer.borderWidth = borderWidth
        }
    }
    
    public var showsCrosshair = true {
        didSet {
            crosshair.isHidden = !showsCrosshair
        }
    }
    
    public var crosshairColor: UIColor = .lightGray {
        didSet {
            crosshair.strokeColor = crosshairColor.cgColor
        }
    }
    
    public var crosshairWidth: CGFloat = 5 {
        didSet {
            crosshair.lineWidth = crosshairWidth
        }
    }
    
    private let crosshair: CAShapeLayer = CAShapeLayer()
    
    public convenience init(offset: CGPoint = .zero, radius: CGFloat = 50, scale: CGFloat = 2, borderColor: UIColor = .lightGray, borderWidth: CGFloat = 3, showsCrosshair: Bool = true, crosshairColor: UIColor = .lightGray, crosshairWidth: CGFloat = 0.5) {
        self.init(frame: .zero)
        layer.masksToBounds = true
        layer.addSublayer(crosshair)
        
        defer {
            self.offset = offset
            self.radius = radius
            self.scale = scale
            self.borderColor = borderColor
            self.borderWidth = borderWidth
            self.showsCrosshair = showsCrosshair
            self.crosshairColor = crosshairColor
            self.crosshairWidth = crosshairWidth
        }
    }
    
    public func magnify(at point: CGPoint) {
        guard magnifiedView != nil else { return }
        magnifiedPoint = point
        layer.setNeedsDisplay()
    }
    
    private func crosshairPath(for radius: CGFloat) -> CGPath {
        let path = CGMutablePath()
        path.move(to: .init(x: radius, y: 0))
        path.addLine(to: .init(x: radius, y: bounds.height))
        path.move(to: .init(x: 0, y: radius))
        path.addLine(to: .init(x: bounds.width, y: radius))
        return path
    }
    
    public override func draw(_ rect: CGRect) {
        guard let context = UIGraphicsGetCurrentContext() else { return }
        
        context.translateBy(x: radius, y: radius)
        context.scaleBy(x: scale, y: scale)
        context.translateBy(x: -magnifiedPoint.x, y: -magnifiedPoint.y)
        
        removeFromSuperview() 
        magnifiedView?.layer.render(in: context) 
        //If above disabled, no change
        //Possible that nothing's being rendered into context
        //Could it be that SKScene view has no layer?

        magnifiedView?.addSubview(self)
    }
}
How would you make a View that magnifies the View(s) beneath it?
 
 
Q