#85 下拉放大圖片(stretchable)的 scroll view

iOS App 有許多酷炫的吸睛動畫,帶給我們良好的使用者體驗。比方使用 Music App 時,下拉歌手個人頁面的 scroll view 將放大歌手的照片。以下圖為例,當頁面從起始位置下拉時,男神張智霖的照片將逐漸放大,讓我們更清楚看到他帥氣的風采。

不僅於此,當頁面從起始位置往上捲動時,照片將逐漸變暗。

接下來就讓我們試試模仿 Music App,親手創作下拉放大文組班文寧同學圖片的 scroll view 吧。

從起始位置往下捲動時,照片將跟著放大
從起始位置往上捲動時,照片將逐漸變暗

ps: 有興趣的朋友也可以猜猜表格裡撩 Swift 的文字改編自哪些經典歌曲。

設計 App 頁面

為了方便 demo,我們在第一個畫面的 view controller 加入 image view,然後用 container view 連結搭配 static cell 的 table view controller。(另一種做法是只用一個 view controller ,在 controller 裡加入 image view & table view。)

設定圖片的 content mode

設為 aspect fill。

設定 auto layout 條件

設定 view controller 裡 container view & image view 的條件,在這裡我們將 image view 的高度條件設為 450,待會往下捲動時,我們將修改高度的條件,增加圖片的高度。

左邊是 container view 的條件,右邊是 image view 的條件

設定畫面的類別 ImageViewController & SongTableViewController

ImageViewController 繼承 UIViewController,SongTableViewController 繼承 UITableViewController。

由於 SongTableViewController 的表格是 static cells,cell 的數量不須從程式控制,記得將以下 2 個 function 移除。

連結圖片高度條件的 outlet imageViewHeightConstraint

class ImageViewController: UIViewController {

@IBOutlet weak var imageViewHeightConstraint: NSLayoutConstraint!

設定表格的 contentInset & 背景顏色

我們希望在表格的上方顯示圖片,而圖片的高度為 450,因此我們定義常數 imageOriginalHeight 儲存高度 450,然後將表格 contentInset 的 top inset 設為 imageOriginalHeight,讓表格的上方多出一塊高度 450 points 的空間。

class SongTableViewController: UITableViewController {
let imageOriginalHeight: CGFloat = 450

override func viewDidLoad() {
super.viewDidLoad()
tableView.contentInset = UIEdgeInsets(top: imageOriginalHeight, left: 0, bottom: 0, right: 0)
}

表格的背景顏色也請記得設為 clear color,如此上方的圖片才不會被表格的背景色覆蓋。

捲動時調整圖片的高度和亮度

定義 protocol UIScrollViewDelegate 的 scrollViewDidScroll(_:),此 function 將在表格捲動時觸發,我們在其中調整圖片的高度和亮度。

override func scrollViewDidScroll(_ scrollView: UIScrollView) {
let controller = parent as? ImageViewController
let originalOffsetY = -imageOriginalHeight
let moveDistance = abs(scrollView.contentOffset.y - originalOffsetY)
if scrollView.contentOffset.y < originalOffsetY {
controller?.imageViewHeightConstraint.constant = imageOriginalHeight + moveDistance
tableView.backgroundColor = UIColor.clear
} else {
controller?.imageViewHeightConstraint.constant = imageOriginalHeight
tableView.backgroundColor = UIColor(white: 0, alpha: moveDistance / imageOriginalHeight)
}
}

說明

let controller = parent as? ImageViewController

利用 parent property 讀取容納 SongTableViewController 的 ImageViewController 物件。

let originalOffsetY = -imageOriginalHeight

由於我們將表格的 top contentInset 設為 imageOriginalHeight,因此它一開始的 contentOffset.y 將等於 -imageOriginalHeight,也就是 -450。

let moveDistance = abs(scrollView.contentOffset.y - originalOffsetY)

計算 scroll view 捲動的距離。往下捲動時 scrollView.contentOffset.y 會愈小,相減的結果將為負數,因此我們利用 abs 讓相減的結果一定為正數。

if scrollView.contentOffset.y < originalOffsetY  {
controller?.imageViewHeightConstraint.constant = imageOriginalHeight + moveDistance
tableView.backgroundColor = UIColor.clear
} else {
controller?.imageViewHeightConstraint.constant = imageOriginalHeight
tableView.backgroundColor = UIColor(white: 0, alpha: moveDistance / imageOriginalHeight)
}

從起始位置往下捲動時 scrollView.contentOffset.y 將小於 originalOffsetY,此時我們修改圖片的高度條件,讓它依據捲動的距離變高。相反的,從起始位置往上捲動時我們將設定表格的背景顏色,讓圖片隨著捲動的距離逐漸變暗。

完整範例連結

那女孩對我說,說我保護她的夢。說這個世界,對 Swift 這樣的不多

作品集

--

--

彼得潘的 iOS App Neverland
彼得潘的 100 道 Swift iOS App 謎題

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