Swift — 製作標籤頁(Tabs) by UICollectionView + UIPageViewController

Tom Tung
7 min readMay 18, 2021

--

Photo by Sigmund on Splash

前言:

前陣子完成 mentor 指派的作業,裡頭需要處理 PageViewController 與 CollectionView 的聯動,當時卡了好一陣子QQ,想說寫個文章給同樣遇到困境的你/妳。那話不多說,先來看個成品:

實作:

首先,畫面分成三個部分 Title(範例),CollectionView(美食、電影、音樂),BottomView(放置PageViewController)

HomeView

一開始,先製作主畫面(HomeView)

CollectionView 會是最麻煩的部分,接下來設置CollectionViewCell

displayTheCurrentPageView 用來顯示所在的頁面

再來加個判斷式

(line 61) 使用動畫讓整個過程有變化的感覺
(line 62)當 Cell 被點選時,會使 backgroundColor 變白,其他未被點選的 Cell 則變為透明

HomeViewController(HomeVC)

一開始做些簡單設置
(line 26) viewDidLoad 時會點選 CollectionView 的第 0 項 IndexPath(item:0, section:0)

再來設置 UICollectionViewDelegateFlowLayout , UICollectionViewDataSource

(line 45~47) 用來設置 cell 的長寬

讓我們來運行看看:

Nice~看來 CollectionView 的部分差不多了,接下來要來處理 PageViewController 了!!

PageViewController

(line 16) 初始化 pageViewController
(line 17) pageViewIndex: 顯示PageView所在頁面,一開始設為 0 ,顯示 viewControllers[0]
(line 18) 新增一個 Array<UIViewController>,裡頭放入 pageViewController 要用的 UIViewController

(line 35,36) HomeVC.view 加入 pageViewController
(line 38) 設置 pageViewController 的 constraints (用到套件 SnapKit),讓它等於 bottomView 的 layout
(line 46) 設置 pageViewController 首頁

再來設置 UIPageViewControllerDelegatePageViewControllerDataSource

(line 105) viewControllerBefore 意思是往前一頁會觸發此 func
(line 111) 同理viewControllerAfter,往後一頁
(line 107) pageViewIndex 是所在的 indexviewControllerBefore 是往前滑 index-1 ,而pageViewToChange 是我自己設的 func ,往下面看~

這個 func 做了簡單的判斷,當傳過來的 index < 0return viewControllers.last (viewController 最後一項) ; 反之,超出 viewControllers 的數量會回到第一項。其他就顯示正常的 viewControllers[index]

接下來就到了重頭戲!!

PageViewController 與 CollectionView 的聯動

首先必須先幫 viewControllers 裡頭的 UIViewController 標記頁數(view.tag)

以 FoodVC 為例

(line 24) view.tag = 0
其他兩個 UIViewController (MovieVC,MusicVC) 依序 1,2
之後要透過view.tag 與 CollectionView 的 index 做互動

第一部分:PageViewController → CollectionView

滑動 pageViewController ,CollectionView 的 displayTheCurrentPageView 會做對應的改變

而 func 不能寫在上面兩種(viewControllerBefore, viewControllerAfter)裡頭,因為這兩種 func 裡的頁面view.tag會處在前一頁到下一頁之間,意思是此時的 view.tag 可能是正確的tag,也可能是還沒滑動時的tag ,就跟薛丁格的貓一樣

因此要確保 PageViewController 滑動結束時才去取view.tag ,而 PageViewController 有個 func 能確保這件事,如下:

(line 120,121) 確保滑動完成時才觸發
(line 124) 此時 vc.view.tag 會是滑動完成後的值
(line 126) 使 collectionView 會點選所在頁數(pageViewIndex),達成滑動 PageViewController → CollectionView 點選

這樣第一部分就完成了~~

第二部分:CollectionView→ PageViewController

點擊 CollectionView ,PageViewController 會跑到指定的頁數,程式如下:

而這裡有個小細節:
如果此時從第一頁(美食) → 第二頁(電影),PageViewController 要是往前滑; 相反的,從第二頁(電影) → 第一頁(美食),要是往後滑,因此要做一個簡單的判斷
(line 88) indexPath.item(點擊的頁數) > pageViewIndex(pageViewController所在的頁數)
(line 90) pageViewController 會以往前(.forward)的方式顯示

這樣作品就完成嘍~

如有任何問題,歡迎留言討論~~

這裡附上作品的 Github:

https://github.com/TomEnChih/TabsExample

--

--

Tom Tung

Hi, I’m Tom. I work as an iOS developer.