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で画像を拡大縮小、スクロールさせる […]