Swift — 製作一個輪播圖吧!

讓我們一起看看如何在 iOS 實作一個可以無限滾動的輪播圖吧!

Jeremy Xue
Jeremy Xue ‘s Blog
Oct 25, 2020

--

Photo by Max Bender on Unsplash

❖ 前言:

最近 iOS Camp 的學員在鐵人賽/合作專案結束之後,開始自主練習 clone 市面上一些 UI 介面稍微比較複雜的 APP。這時他們很常碰到需要實作同一個頁面中多個畫面切換轉場的功能,然後我就告訴他們可以嘗試使用看看 UIPageViewController,看看這種控制器的功能是否符合你的需求。

然後,第二個比較多人碰到的問題就是輪播圖(Carousel)。我相信單純要實現輪播圖的 UI 或是定時滾動的功能是非常容易的。但一旦要考慮到使用者操作的話往往就不是那麼簡單的可以處理好的。假設這個輪播圖還需要加上無限滾動(例如:A, B, C -> A, B, C 以此類推)的效果的話,想必也是一門學問。

在過去,我在實作這種輪播圖功能的時候,可能會想要採用 UIScrollView + ImageView,或是 UICollectionView + Cell 來製作。但是後來學到更多技術後,感覺上使用 UIPageViewController 來實作是最容易製作輪播圖所需要的各種功能面上的效果,而且十分直覺。那麼,我就來帶著大家使用 UIPageViewController 來實作輪播圖效果吧!

❖ 實作輪播圖:

1. 畫面結構說明:

先來看一張畫面結構圖:

  • ViewController :放置輪播圖的控制器(畫面左側)。其中的 UIView 為輪播圖所在位置,並將其作為 ContainerView 嵌入畫面中的 PageViewController
  • PageViewController:輪播圖的核心控制器(畫面中間),我們會在此控制器中配置我們輪播圖中的內容,同時也會在這邊實作其他輪播圖的相關功能(顯示 index、無限輪播…)
  • ImageViewController:輪播圖的內容控制器(畫面右側)。單純用來顯示輪播圖內容。

記住,這邊顯示輪播圖的內容控制器只需要一個即可,我們可以重複產生同一個控制器來顯示內容(有點類似於 TableViewCellCollectionViewCell 的概念)。並不會因為你今天要顯示多個輪播圖而建立多個內容控制器。這是一個錯誤的觀念。

常常看到有人會建立 ContentViewController1ContentViewController2ContentViewController3 之類的內容控制器,但是在每個控制器上所要顯示的內容都是相同的,除非你的內容是完全不同的內容,否則沒有這個必要。因此正確的方式應該是使用同一個內容控制器,並且重複產生三個即可。

‍❌ 錯誤的方式(除了內容不同)
viewControllers = [
ContentViewController1()
ContentViewController2()
ContentViewController3()
]
⭕️ 正確的方式(當顯示內容都相同時)
viewControllers = [
ContentViewController()
ContentViewController()
ContentViewController()
]

2. 設置 PageViewController 的滾動方向和轉場模式

別忘了將 PageViewControllerTransition Style 設置為 Scroll,並且 NavigationHorizontal

3. 配置 ImageViewController

這邊我們簡單幫 ImageViewController 加上一個類似於帶入 UIImage? 的初始化器(這邊由於是透過 storyboard 的方式才會編寫此 instantiate 函數,如果是純 code/xib 則使用 init 方式即可),並且 imageView 會在 viewDidLoad 後設置其 image

4. 配置 PageViewController

PageViewController 中,我們會建立所需的內容控制器(在此為ImageViewController),接著我們還需要在 setup 函數中設置 PageViewController 中的初始畫面,我們可以調用 PageViewController 中的 setViewControllers 方法來達成:

看看畫面上是否出現對應的圖片吧:

接著下一步我們來設置輪播圖中的手勢滑動功能,這邊我們先在 setup 函數中將 dataSource 以及 delegate 設為 self,我們之後會透過其 dataSource 方法告訴 PageViewController 前一個以及後一個的內容控制器該為哪一個。並且透過 delegate 中的方法來更新目前在 viewControllers 中的 index

首先,讓我們宣告一個 currentIndex 來儲存並作為目前顯示的控制器在 imageViewControllers 中的 index

接著,我們先編寫一個 getImageViewController 函數來透過 index 獲取我們在 imageViewControllers 中的控制器,並且在不包含的狀況下返回 nil

接著,我們在 UIPageViewControllerDataSource 調用此方法,告訴 PageViewController 前/後一個控制其為誰:

最後,我們需要實現下列這個 UIPageViewControllerDelegate 中的方法,我們會藉由此函數獲取目前畫面上所顯示的控制器,並且透過他來更新我們目前在 imageViewcontrollersindex 並賦給 currentIndex 來達成更新當前索引的目的。

接著就讓我看看實際上的效果吧!

如此一來我們就達成輪播圖的基本效果了。是不是非常容易呢!

接下來如果你想要實現無限輪播的功能的話,我們只需要稍微調整上述getImageViewController 函數中的內容即可。我們會在 index < 0 的時候,給與最後一個控制器;在 index > imageViewControllers 的數目時,給予第一個控制器,如下:

接著,再讓我們運行一次程式碼看看結果吧!

如此一來我們就輕輕鬆鬆的使用 UIPageViewController 來達成我們輪播圖的功能製作了。

後記:

之前因為有特別研究過 UIPageViewController,所以對此控制器有一定程度的概念,然後剛好又碰上輪播圖的功能,覺得使用 UIPageViewController 來實作會非常容易並且直覺,又可以獨立到一個 Controller 中相關處理事情,之後也可以透過 currentIndexsetViewControllers 來做到顯示索引或是控制顯示特定畫面的目的。

之後有時間的話再來補上之前在 UIPageViewController 上所研究到的內容,覺得真的是一個蠻特別的控制器元件,而大多數的文章中好像都沒有提及太多相關內容,有時間再來慢慢補上。

--

--

Jeremy Xue
Jeremy Xue ‘s Blog

Hi, I’m Jeremy. [好想工作室 — iOS Developer]