import UIKit final class RDEPUBSelectionLoupeView: UIView { private let imageView = UIImageView() private let magnification: CGFloat = 1.45 private let captureSize = CGSize(width: 84, height: 84) override init(frame: CGRect) { super.init(frame: CGRect(origin: .zero, size: CGSize(width: 96, height: 96))) isUserInteractionEnabled = false backgroundColor = .clear layer.shadowColor = UIColor.black.cgColor layer.shadowOpacity = 0.18 layer.shadowRadius = 10 layer.shadowOffset = CGSize(width: 0, height: 5) imageView.frame = bounds imageView.autoresizingMask = [.flexibleWidth, .flexibleHeight] imageView.layer.cornerRadius = bounds.width / 2 imageView.layer.cornerCurve = .continuous imageView.layer.borderWidth = 1.5 imageView.layer.borderColor = UIColor(white: 0.82, alpha: 0.95).cgColor imageView.clipsToBounds = true addSubview(imageView) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func present(sourceView: UIView, focusPoint: CGPoint, hostBounds: CGRect, targetPoint: CGPoint) { imageView.image = snapshot(from: sourceView, focusPoint: focusPoint) let targetCenter = CGPoint( x: min(max(targetPoint.x, hostBounds.minX + bounds.width / 2), hostBounds.maxX - bounds.width / 2), y: min( max(hostBounds.minY + bounds.height / 2, targetPoint.y - 74), hostBounds.maxY - bounds.height / 2 ) ) center = targetCenter if isHidden { alpha = 0 transform = CGAffineTransform(scaleX: 0.92, y: 0.92) isHidden = false UIView.animate(withDuration: 0.12) { self.alpha = 1 self.transform = .identity } } } func dismiss() { guard !isHidden else { return } isHidden = true alpha = 0 imageView.image = nil } private func snapshot(from sourceView: UIView, focusPoint: CGPoint) -> UIImage { let renderer = UIGraphicsImageRenderer(size: captureSize) return renderer.image { context in let cgContext = context.cgContext cgContext.setFillColor(UIColor.systemBackground.cgColor) cgContext.fill(CGRect(origin: .zero, size: captureSize)) cgContext.translateBy( x: captureSize.width / 2 - focusPoint.x * magnification, y: captureSize.height / 2 - focusPoint.y * magnification ) cgContext.scaleBy(x: magnification, y: magnification) sourceView.layer.render(in: cgContext) } } }