利用 scroll view & contentInset 縮放置中圖片

利用 scroll view 內建的縮放功能,我們可以快速實現圖片縮放的功能。接下來就讓我們以電影孤味的圖片為例,一步步實現吧。

加入 scroll view

讓 scroll view 佔滿螢幕

選取 view & scroll view,設定上下左右的間距為 0。

此時由於 scroll view 還無法推算捲動範圍的大小,因此將出現紅色錯誤。

將 image view 加到 scroll view 上

讓 scroll view 的捲動範圍等於 image view 的大小

選取 image view & content layout guide,設定上下左右的間距為 0。

content layout guide 可決定 scroll view 的捲動範圍,相關說明可參考以下連結。

加了條件後,scroll view 可以計算捲動範圍,因此不再有紅色錯誤。如下圖所示,此時捲動範圍等於 image view 的大小。

image view 的大小預設等於圖片的大小,因此 image view 的大小為 1024 * 581 points,形成可以左右捲動的 scroll view。

大功告成了嗎? 別急,還有一些小細節要處理。我們希望圖片一開始可以完整在螢幕呈現,而且還能放大縮小,所以請繼續看下去。

連結 image view & scroll view 的 outlet

我們待會將從程式存取 image view & scroll view,所以要先拉 outlet。

@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var imageView: UIImageView!

調整 scroll view 縮放的比例,讓圖片完整呈現

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

updateZoomSizeFor(size: view.bounds.size)
}

func updateZoomSizeFor(size: CGSize) {
let widthScale = size.width / imageView.bounds.width
let heightScale = size.height / imageView.bounds.height
let scale = min(widthScale, heightScale)
scrollView.minimumZoomScale = scale
scrollView.zoomScale = scale

}

我們希望原本超出螢幕的大張圖片完整呈現,因此我們需要將圖片縮小。scroll view 內建縮放功能,可以幫我們縮放圖片。在此我們利用 min(widthScale, heightScale) 計算圖片想在螢幕完整呈現須縮放的比例,調整 scroll view 的 minimumZoomScale & zoomScale。

設定 scroll view 的 delegate 為 view controller

為了告訴 scroll view 縮放的元件是 image view,我們必須透過 scroll view 的 delegate function,因此我們將 controller 設為 scroll view 的 delegate。

利用 extension 讓 ViewController 遵從 protocol UIScrollViewDelegate

extension ViewController: UIScrollViewDelegate {

}

定義 UIScrollViewDelegate 控制縮放對象的 function viewForZooming(in:)

回傳 imageView,因此圖片將成為縮放的對象。

extension ViewController: UIScrollViewDelegate {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
imageView
}
}

測試 App

Cool,現在我們可以成功縮放圖片了。不過有個小地方令人不太滿意,我們的圖片一開始會置頂,如果能置中該有多好 ?

模擬器的縮放手勢可參考以下連結。

利用 contentInset 置中縮放的圖片

想置中的話,我們可利用 scroll view 的 contentInset 實現。如下圖所示, 在 scroll view 的上下左右可加入稱為 contentInset 的空白區塊

在剛剛的例子,我們的圖片頂置。如果我們能在它的上方加入 content inset,即可讓圖片往下移動,變成置中顯示。

但是要往下移動多少呢 ? 利用 scroll view 的高度減圖片縮放後的高度,然後再除以 2,即為 content inset top 需要的高度。(imageView.frame.height 將是圖片縮放後的高度,它會等於imageView.bounds.height * scrollView.zoomScale )

(scrollView.bounds.height - imageView.frame.height) / 2

因此我們在 extension ViewController 定義 UIScrollViewDelegate 的 function scrollViewDidZoom(_:)。此 function 將在 scroll view zoomScale 改變時被觸發,因此我們可在裡面調整 scroll view 的 content inset。

func scrollViewDidZoom(_ scrollView: UIScrollView) {
let inset = (scrollView.bounds.height - imageView.frame.height) / 2
scrollView.contentInset = .init(top: max(inset, 0), left: 0, bottom: 0, right: 0)

}

調整 content inset 後,圖片順利置中了 !

若圖片的尺寸小於螢幕尺寸

scroll view 預設的 maximumZoomScale 是 1,若圖片的尺寸小於螢幕尺寸,想要它佔滿螢幕時,需將 maximumZoomScale 設為大於 1 才能放大。

因此我們可利用 max(widthScale, heightScale) 計算放大的比例,設定 scroll view 的 maximumZoomScale。

func updateZoomSizeFor(size: CGSize) {
let widthScale = size.width / imageView.bounds.width
let heightScale = size.height / imageView.bounds.height
let scale = min(widthScale, heightScale)
scrollView.minimumZoomScale = scale
scrollView.maximumZoomScale = max(widthScale, heightScale)
scrollView.zoomScale = scale
}

圖片成功放大到全螢幕。

範例連結

其它圖片縮放的套件參考

參考連結

Lesson 1.4 Lab I Spy — Develop in Swift Data Collections

--

--

彼得潘的 iOS App Neverland
彼得潘的 Swift iOS App 開發問題解答集

彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,彼得潘的 Swift 程式設計入門,App程式設計入門作者,http://apppeterpan.strikingly.com