#83 製作 IG 滑動後 profile tab 卡在上方的效果

模仿 IG App,製作照片牆滑動後 profile tab 卡在上方的效果。

有很多方法可以實現,以下示範利用 collection view,section top inset & auto layout 條件實現。

利用 flow layout 的 collection view 製作照片牆

參考以下連結,以繼承 UICollectionViewController 的 PrinceCollectionViewController 撰寫照片牆的程式。

設定 Section 的 Top inset

我們希望在照片牆的上方顯示 profile 資訊區塊,而區塊的高度為 413,因此我們將 section 的 top inset 設為 413,讓 cell 的上方多出一塊高度 413 points 的空間。

左邊是一開始的畫面,有著高度 413 的 top inset,右邊則是向上滑動後的畫面

我們也可以從程式設定 section inset,透過定義 protocol UICollectionViewDelegateFlowLayout 的 collectionView(_:layout:insetForSectionAt:)。

class PrinceCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {   func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {      return UIEdgeInsets(top: 413, left: 0, bottom: 0, right: 0)}

加入 profile 資訊區塊的圖片

為了簡化程式,我們先偷懶用 image view 顯示圖片 profile,呈現 profile 資訊區塊。實際開發 App 時,再將它換成容納其它元件的 view 或 stack view 即可。

將 profile 資訊區塊加到 collection view

修改 viewDidLoad,將 profile 資訊區塊加到 collection view。

override func viewDidLoad() {   super.viewDidLoad()   let profileImageView = UIImageView(image: UIImage(named: "profile"))   profileImageView.translatesAutoresizingMaskIntoConstraints = false   collectionView.addSubview(profileImageView)   profileImageView.heightAnchor.constraint(equalToConstant: 413).isActive = true   profileImageView.leadingAnchor.constraint(equalTo: collectionView.frameLayoutGuide.leadingAnchor).isActive = true   profileImageView.trailingAnchor.constraint(equalTo: collectionView.frameLayoutGuide.trailingAnchor).isActive = true   let topConstraint = profileImageView.topAnchor.constraint(equalTo: collectionView.contentLayoutGuide.topAnchor)   topConstraint.priority = UILayoutPriority(999)   topConstraint.isActive = trueprofileImageView.bottomAnchor.constraint(greaterThanOrEqualTo: collectionView.safeAreaLayoutGuide.topAnchor, constant: 40).isActive = true   let width = (collectionView.bounds.width - 1 * 2) / 3   let flowLayout = collectionViewLayout as? UICollectionViewFlowLayout   flowLayout?.itemSize = CGSize(width: width, height: width)   flowLayout?.estimatedItemSize = .zero}

說明

  • 將 profileImageView 加到 collection view。
let profileImageView = UIImageView(image: UIImage(named: "profile"))
profileImageView.translatesAutoresizingMaskIntoConstraints = false
collectionView.addSubview(profileImageView)
  • 設定 profileImageView 的 auto layout 條件。
profileImageView.heightAnchor.constraint(equalToConstant: 413).isActive = trueprofileImageView.leadingAnchor.constraint(equalTo: collectionView.frameLayoutGuide.leadingAnchor).isActive = trueprofileImageView.trailingAnchor.constraint(equalTo: collectionView.frameLayoutGuide.trailingAnchor).isActive = truelet topConstraint = profileImageView.topAnchor.constraint(equalTo: collectionView.contentLayoutGuide.topAnchor)topConstraint.priority = UILayoutPriority(999)topConstraint.isActive = trueprofileImageView.bottomAnchor.constraint(greaterThanOrEqualTo: collectionView.safeAreaLayoutGuide.topAnchor, constant: 40).isActive = true

為了方便使用者切換照片牆,頁面滑動時 profile tab 將卡在上方,因此我們模仿 frame layout guide 設計浮動元件的技巧實現。對 scroll view 的 frame layout guide & content layout guide 不熟的朋友可參考以下連結。

設定 auto layout 條件時,我們讓圖片的下邊界(也是 profile tab 的下邊界)跟 safe area 的上邊界至少有著 40 points 的間距,如此即可讓頁面 scroll 到一定程度時,profile tab 仍會固定在上方。不過為了解決衝突,記得要將圖片和 contentLayoutGuide 上邊界對齊條件的 property 降為 999。

從 Interface Builder 設計 profile 區塊

除了從程式設計 profile 區塊,我們也可以從 Interface Builder 設計後再從程式加入,相關說明可參考以下連結。

範例連結

作品集

--

--

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

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