Zooming image by viewForZooming in UIScrollViewDelegate.


extension ImageDetailVC {
    static var instance: ImageDetailVC {
        return UIStoryboard(name: "ImageDetailVC", bundle: nil)
            .instantiateViewController(withIdentifier: "ImageDetailVC") as! ImageDetailVC
    }
}

class ImageDetailVC: ViewController {
    
    @IBOutlet private weak var scrollView: UIScrollView!
    
    private var imageView: UIImageView!
    var image: UIImage!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        initDoubleTapGesture()
        initImageView()
    }
    
    private func initDoubleTapGesture() {
        let tap = UITapGestureRecognizer(target: self, action: #selector(doubleTap(_:)))
        tap.numberOfTapsRequired = 2
        scrollView.addGestureRecognizer(tap)
    }
    
    @objc private func doubleTap(_ gesture: UITapGestureRecognizer) {
        if self.scrollView.zoomScale == 1 {
            zoom(to: gesture.location(in: imageView))
        } else {
            UIView.animate(withDuration: 0.3) {
                self.scrollView.zoomScale = 1
            }
        }
    }
    
    private func zoom(to point: CGPoint) {
        let width = scrollView.bounds.width / 3
        let height = scrollView.bounds.height / 3
        let x = point.x - width / 2
        let y = point.y - height / 2
        let frame = CGRect(x: x, y: y, width: width, height: height)
        scrollView.zoom(to: frame, animated: true)
    }
    
    private func initImageView() {
        imageView = UIImageView(image: image)
        imageView.contentMode = .scaleAspectFit
        scrollView.addSubview(imageView)
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        imageScale()
    }
    
}

extension ImageDetailVC: UIScrollViewDelegate {
    
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return imageView
    }
    
    func scrollViewDidZoom(_ scrollView: UIScrollView) {
        imageScale(at: scrollView.zoomScale)
    }
    
    private func imageScale(at zoom: CGFloat = 1) {
        let ratioSize = AVMakeRect(aspectRatio: image.size, insideRect: scrollView.bounds).size
        let width = ratioSize.width * zoom
        let height = ratioSize.height * zoom
        let x = (scrollView.bounds.width - width) / 2
        let y = (scrollView.bounds.height - height) / 2
        imageView.frame = CGRect(x: max(0, x), y: max(0, y), width: width, height: height)
    }
    
}

extension ImageDetailVC {
    
    @IBAction private func save(_ sender: UIBarButtonItem) {
        PHPhotoLibrary.requestAuthorization { status in
            DispatchQueue.main.async {
                if status == .authorized {
                    UIImageWriteToSavedPhotosAlbum(self.image, self, #selector(self.saved(_:error:info:)), nil)
                } else {
                    Util.privacyAlert(msg: .album) // 설정 요청 알림
                }
            }
        }
    }
    
    @objc private func saved(_ image: UIImage, error: NSError?, info: UnsafeRawPointer) {
        if let error = error {AlertBar.show(error.localizedDescription)}
        else {AlertBar.show(.photoSaved)} // 사진 저장 알림
    }
    
}