👻

pinchとdouble tapでzoomするUIImageViewを作る

2020/12/14に公開

ピンチイン/アウトでズームアウト/インをして、さらにダブルタップで何段階かに拡大して元の縮尺に戻るUIImageViewを作成したので簡単にメモ。

ピンチでズームするUIImageView

UIScrollViewを使ってUIImageViewをピンチでズームするコードは検索すればいくらでも出てくるが一応手順を記録しておく。

UIScrollViewの中にUIImageViewを置く

まずはズームしたいUIImageViewUIScrollViewの中に置く必要がある。
これはStoryboardで行う場合にはUIImageViewを選択してからEditorメニューのEmbed inScroll Viewを選択する。

コードの場合はUIScrollViewaddSubview(_ view:)で行う。

scrollView.addSubview(imageView)

UIScrollViewのdelegateを設定

Storyboardでも繋げるしUIViewControllerのコードで書いても良い

zoomByPinchDoubleTap.swift
scrollView.delegate = self

UIScrollViewのmaximumZoomScaleを設定

デフォルトではmaximumZoomScaleが1になっているのでそのままだとズームしない。
今回は4倍までズームするようにした。

zoomByPinchDoubleTap.swift
self.scrollView.maximumZoomScale = 4.0

UIViewControllerをUIScrollViewDelegateプロトコルに対応する

UIScrollViewDelegateに必須の関数はないがズームにはviewForZooming(in:)が必要。返す値はUIScrollViewに含まれるUIImageView

zoomByPinchDoubleTap.swift
    func viewForZooming(in scrollView: UIScrollView) -> UIView? {
        return imageView
    }

以上でUIImageVIewをピンチでズームできるようになる。

今回はダブルタップで2倍、4倍にズームできるようにする必要があったので更に後述するUITapGestureRecognizerを使用している。

ダブルタップでズームするようにする

これはを行うにはUITapGestureRecognizerを使用してイベントを取得し、マニュアルで画像サイズを変更する。

手順としては以下の通り。

UIScrollViewにUITapGestureRecognizerを設定

UIScrollViewがダブルタップに反応するようにUITapGestureRecognizerをセットする。
UITapGestureRecognizerはダブルタップに反応するようにnumberOfTapRequiredを2に設定している。

zoomByPinchDoubleTap.swift
        let recognizer = UITapGestureRecognizer(target: self,
                                                action: #selector(onDoubleTap(_:)))
        recognizer.numberOfTapsRequired = 2
        scrollView.addGestureRecognizer(recognizer)

ダブルタップ時のアクションに画像をズームするコードを書く

具体的にはUIScrollViewの大きさとscaleから画像の表示される範囲を計算して、UIScrollViewをその範囲にズームしている。
また、既に最大の4倍までズームされている場合には1倍の状態に戻している。

zoomByPinchDoubleTap.swift
    @objc func onDoubleTap(_ sender: UITapGestureRecognizer) {
        let scale = min(scrollView.zoomScale * 2, scrollView.maximumZoomScale)
        
        if scale != scrollView.zoomScale {
            let tapPoint = sender.location(in: imageView)
            let size = CGSize(width: scrollView.frame.size.width / scale,
                              height: scrollView.frame.size.height / scale)
            let origin = CGPoint(x: tapPoint.x - size.width / 2,
                                 y: tapPoint.y - size.height / 2)
            scrollView.zoom(to: CGRect(origin: origin, size: size), animated: true)
        }
        else {
            scrollView.zoom(to: scrollView.frame, animated: true)
        }
    }

コード

ピンチとダブルタップでズームするUIImageViewを使ったViewControllerのコードはGitHubに置いてある。
https://gist.github.com/paraches/ca58b5acb0585d5080feaaa5fa869998

Discussion