在Web領域我們已經經常能夠看到捲動視差(Parallax Scrolling)的效果了,尤其是在一些著陸頁(Landing Page),經常會用這種效果。
圖片類的應用除了瀑布流的排版(Masonry Layout)以外,這個也是個不錯的排版效果,接下來讓我們來實現一下。
捲動視差效果
動手做捲動視差動畫
視差效果原理
想像一下,現在我們的「眼睛」透過一面「窗戶」來看「風景」,當至少其中一個進行上下移動的時候,可以看到風景的部分就會產生變化。
而為了在手機畫面上能實現這樣的效果,我們需要準備一張比Cell還大的一張圖片
屏幕相當於我們的眼睛,而屏幕是不能移動的,所以我們可以通過移動Cell或者ImageView來產生視差效果。
而ImageView大於Cell的這個30px(140px – 110 px),其實就是視差範圍,畢竟我們希望不出現圖片以外的內容。
實現步驟
假設我們使用的是UICollectionView,希望在滑動的時候讓cell中的圖片呈現視差捲動的效果。
我們以View的中心為標準,
- 當Cell在CollectionView的中間時,ImageView的中心也在Cell的中心。
- 當Cell在CollectionView的頂部時,ImageView也在頂部。
- 當Cell在CollectionView的底下時,ImageView也在底下。
UIScrollViewDelegate
要達到這樣的效果,首先我們需要實現UIScrollViewDelegate的方法,當畫面滑動的時候通知所有在畫面上的cell。
1 2 3 4 5 6 7 8 9 10 11 12 |
// MARK: UIScrollViewDelegate extension HomeViewController: UIScrollViewDelegate { func scrollViewDidScroll(_ scrollView: UIScrollView) { // 當UICollectionView被拖動的時候,通知出現在畫面上的cell for cell in aCollectionView.visibleCells { if let homeCell = cell as? HomeCell { homeCell.cellOnTableView(collectionView: aCollectionView, didScrollOnView: view) } } } } |
Cell
在Cell中提供一個方法,可以計算出cell位於View(CollectionView的superView)的座標系統中的距離中心點的位移情況。
根據這個位移的情況來計算視差的的移動比例,進而改變現在imageView的frame。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
func cellOnTableView(collectionView:UICollectionView, didScrollOnView view:UIView) { // 取得cell在collectionView中,相對view座標系統的frame let rectInSuperview = collectionView.convert(self.frame, to: view) // 位移相對中心點的距離 let distanceFromCenter = view.frame.height/2 - rectInSuperview.minY // 圖片大於cell高度的部分,也就是視差的高度 let parallaxHeight = imageView.frame.height - frame.height // 以cell相對view中心點移動的距離,來計算視差的移動距離 let move = (distanceFromCenter / view.frame.height) * parallaxHeight // 先將imageView向上移動一半的視差高度(difference/2),然後根據move程度變化y的位置 var imageRect = imageView.frame imageRect.origin.y = -(parallaxHeight/2) + move // 給予imageView一個新的frame,達到視差效果。 imageView.frame = imageRect } |
而為了讓畫面第一次呈現時就讓imageView擁有正確的frame,我們在畫面第一次顯示的時候就觸發cell計算一次frame。
1 2 3 4 |
override func viewDidAppear(_ animated: Bool) { // 畫面第一次出現時就先計算cell中的offset scrollViewDidScroll(aCollectionView) } |
推薦與參考
- 歡迎分享本文「Swift 實現視差捲動效果(Parallax Scrolling)」 – https://ios.devdon.com/archives/643
- 進一步瞭解UIView的座標系統及其轉換方法。
- 本文在Gihub上的SourceCode – 「Swift實現捲動視差效果」