Swift3で、ピンチイン、アウトで画像の拡大縮小、スクロールをさせる必要があり、いくつか試行錯誤したのでその覚書です。
ソースコード
サンプルの画像を一枚表示して、拡大、縮小、スクロールするだけのデモアプリです。ソースコードは以下の通りです。
// // ViewController.swift // zoom-scroll-demo-app // // Created by Tetsuo Yutani on 2018/01/04. // Copyright © 2018 Tetsuo Yutani. All rights reserved. // import UIKit import os.log class ViewController: UIViewController, UIScrollViewDelegate { @IBOutlet weak var scrollView: UIScrollView! var imageView: UIImageView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. scrollView.delegate = self // Scale factor can be changed from 0.0 to 2.0 scrollView.minimumZoomScale = 0.0 scrollView.maximumZoomScale = 2.0 imageView = UIImageView(image: UIImage(named: "sample.jpg")) imageView.contentMode = .scaleAspectFit scrollView.addSubview(imageView) } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() if let image = imageView.image { let w_scale = scrollView.frame.width / image.size.width let h_scale = scrollView.frame.height / image.size.height // Fit longer edge to screen // let scale = min(w_scale, h_scale) // Fit shorter edge to screen let scale = max(w_scale, h_scale) // Not zoom, only scroll // scrollView.minimumZoomScale = scale // scrollView.maximumZoomScale = scale scrollView.zoomScale = scale scrollView.contentSize = imageView.frame.size // In case that the image is larger than screen, calculate offset to show the center of image at initial launch let offset = CGPoint(x: (imageView.frame.width - scrollView.frame.width) / 2.0, y: (imageView.frame.height - scrollView.frame.height) / 2.0) scrollView.setContentOffset(offset, animated: false) } } func viewForZooming(in scrollView: UIScrollView) -> UIView? { return imageView } func scrollViewDidZoom(_ scrollView: UIScrollView) { // Keep the image at center of the screen in case that the image is smaller than the screen scrollView.contentInset = UIEdgeInsetsMake( max((scrollView.frame.height - imageView.frame.height) / 2.0, 0.0), max((scrollView.frame.width - imageView.frame.width) / 2.0, 0.0), 0, 0 ); } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
デモアプリの全コードはgithubに置いています。
Storyboard
このアプリはUIScrollViewの上にUIImageViewを置いて、そこに画像を表示させています。ですので、storyboardでViewControllerの前面にUIScrollViewを置きます。
次に、UIScrollViewを選択してAttributes inspectorを表示させます。アトリビュートの中の”Zoom”のMinとMaxの値を変更します。デフォルトでは両方とも1ですので、そのままでは拡大も縮小もできません。デモアプリではコード内で以下のように設定していますが、そうしない場合はこのアトリビュートを適切に設定しなければなりません。
// Scale factor can be changed from 0.0 to 2.0 scrollView.minimumZoomScale = 0.0 scrollView.maximumZoomScale = 2.0
さらにその上にUIImageViewを配置しても良いですが、デモアプリでは次のようにコード内でUIImageViewを配置しています。
imageView = UIImageView(image: UIImage(named: "sample.jpg")) imageView.contentMode = .scaleAspectFit scrollView.addSubview(imageView)
拡大縮小
addSubView() を使ったので、viewDidLayoutSubview の中で拡大縮小の設定等をしています。デフォルトのscaleは1なので、そのままでは画像がdot by dotで表示されてしまいます。画像の大きさとScrollViewの大きさから縮小率を計算して、scrollView.zoomScale に設定します。
let w_scale = scrollView.frame.width / image.size.width let h_scale = scrollView.frame.height / image.size.height // Fit longer edge to screen // let scale = min(w_scale, h_scale) // Fit shorter edge to screen let scale = max(w_scale, h_scale)
w_scaleとh_scaleの小さい方を使えば画像全体が表示されます。逆に、大きい方を使えば画像が画面いっぱいに表示されます。
なお、拡大縮小したくないときは、ズームの上限と下限を同じに設定します。
// Not zoom, only scroll scrollView.minimumZoomScale = scale scrollView.maximumZoomScale = scale
最後に、拡大縮小した画像を表示するためには次のコードが必要です。
func viewForZooming(in scrollView: UIScrollView) -> UIView? { return imageView }
画像を画面の中央に表示する
画像を縮小して画面より小さくすると、画像は画面の左上に表示されてしまいます。常に画像を画面の中央に表示するためには次のようにします。
func scrollViewDidZoom(_ scrollView: UIScrollView) { // Keep the image at center of the screen in case that the image is smaller than the screen scrollView.contentInset = UIEdgeInsetsMake( max((scrollView.frame.height - imageView.frame.height) / 2.0, 0.0), max((scrollView.frame.width - imageView.frame.width) / 2.0, 0.0), 0, 0 ); }
画面より大きな画像の中央を表示する
画面より大きな画像の場合、最初に表示された時、画像の左側が表示されてしまいます。画像の中央を表示したい場合は、viewDidLayoutSubviewで以下のようにします。
// In case that the image is larger than screen, calculate offset to show the center of image at initial launch let offset = CGPoint(x: (imageView.frame.width - scrollView.frame.width) / 2.0, y: (imageView.frame.height - scrollView.frame.height) / 2.0) scrollView.setContentOffset(offset, animated: false)
最後に
UIScrollViewを使うだけで簡単に拡大縮小とスクロールを実現できました。もっと細かい制御をしたい場合はジェスチャーを使うのが良さそうですが、通常の用途はUIScrollViewだけで十分でしょう。
コメント
[…] Scroll View Programming Guide for iOS UIScrollView And Autolayout Swift3で画像を拡大縮小、スクロールさせる […]