#33 Use UITableViewController with dynamic prototypes to imitate Apple Music
先前在製作表格都是使用 static cells,一格一格從 Storyboard 去設定各個 cell 的圖片及文字,今天要來記錄如何直接從程式去設定每一格 cell 的內容。
Target
- 使用 Dynamic prototypes 從程式設計表格
- 客製表格內的元件
Process
Step 1: Add component to Main storyboard
由於是從程式去設計表格,所以在 Main storyboard 的畫面看起來非常簡單,就是一個 Tab Bar Controller、一個 Navigation Controller 和一個 TableView Controller,然後 TableView Controller 裡的 cell 新增一個 ImageView、兩個 Label 、一個 Button,就醬。
Step 2: Add Cocoa Touch Class
如何增加這裡就不再贅述了,但要特別提醒的一點是,除了新增 UITableViewController class 以外,由於這次要客製化表格內容,所以必須還要再新增一個 UITableViewCell class。
新增完之後,記得要到 Identity Inspector 去改 Class,包含 TableViewCell 也要一併改掉。
Step 3: Add IBOutlet into the new UITableViewCell class
這裡要特別提一下一個很容易忘記的地方,以往我們拉 IBOutlet 都會拉到 ViewController class 裡面,但因為這次是 TableViewController,所以我們應該直接拉到 TableViewController class 裡面嗎?
Wrong!
我們的目標是要讓每一個 cell 裡面的圖都顯示各自所對應的專輯畫面,如果我們拉一個 IBOutlet 到整個 TableViewController class,這樣似乎有點奇怪,為什麼會奇怪?
我們程式裡面只有一個變數,但這個變數要同時顯示不一樣的圖片,這好像說不通。
所以應該要拉到 TableViewCell 的 class 裡面才對,之後用 indexPath.row 去讀取指定列的指定圖片即可。
可以點選 Content View 後,利用上圖右上角處去切換 TableViewCell class 和 TableViewController class。
Step 4: Coding
再來就是回到 TableViewController class 去完成剩下的 code 了。由於這是第一次在 TableViewController class 寫 code 。所以這邊還是記錄一下過程。
當你打開時,可以看到除了原本我們熟悉的 viewDidLoad() 以外,可以看到多了兩段程式碼如下:
override func numberOfSections(in tableView: UITableView) -> Int {// #warning Incomplete implementation, return the number of sectionsreturn 0}override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {// #warning Incomplete implementation, return the number of rowsreturn 0}
可以猜得到,第一段最後 return 的數字代表有幾個 section,第二段最後 return 的數字代表每一個 section 裡面有幾個 row。若依照 Apple Music 的介面來看,有一個 section ,至於幾個 row 就看你有幾筆資料要呈現,所以我會先建立一個 Array 儲存資料。
var cellInfos: [CellInfo] = [CellInfo(albumImage: "pic1", songName: "出走", artist: "蔡健雅"),CellInfo(albumImage: "pic2", songName: "我一直都在這裡 (電影《熊出沒·狂野大陸》主題曲)", artist: "徐佳瑩"),CellInfo(albumImage: "pic3", songName: "Permission to Dance", artist: "防彈少年團"),CellInfo(albumImage: "pic4", songName: "NDA", artist: "Billie Eilish"),CellInfo(albumImage: "pic5", songName: "Motley Crew", artist: "Post Malone"),CellInfo(albumImage: "pic6", songName: "could cry just thinkin about you (Full Version)", artist: "Troye Sivan"),CellInfo(albumImage: "pic7", songName: "NOW I'M ALONE (feat. Sofía Valdés)", artist: "HONNE"),CellInfo(albumImage: "pic8", songName: "Stay", artist: "The Kid LAROI & Justin Bieber"),CellInfo(albumImage: "pic9", songName: "Crowd Go Crazy", artist: "John Legend"),CellInfo(albumImage: "pic10", songName: "並不是夕陽美景 (Songs Of Stories 03.)", artist: "Control T"),CellInfo(albumImage: "pic11", songName: "Stranger Things (feat. Karra)", artist: "Lizzy Wang"),CellInfo(albumImage: "pic12", songName: "Wrecked", artist: "Imagine Dragons"),CellInfo(albumImage: "pic13", songName: "Better Off Without You (feat. 瘦子E.SO)", artist: "吳卓源"),CellInfo(albumImage: "pic14", songName: "In My Toes", artist: "陳芳語"),CellInfo(albumImage: "pic15", songName: "Jurassic Ride", artist: "恐龍的皮"),CellInfo(albumImage: "pic16", songName: "潮隙", artist: "AD & 四枝筆"),CellInfo(albumImage: "pic17", songName: "You for Me", artist: "Sigala & Rita Ora"),CellInfo(albumImage: "pic18", songName: "Yellow Cab", artist: "DPR LIVE"),CellInfo(albumImage: "pic19", songName: "We Know (feat. BG8LOCC & Allen Flex)", artist: "婁峻碩"),CellInfo(albumImage: "pic20", songName: "夢想的台北", artist: "魏妙如"),CellInfo(albumImage: "pic21", songName: "プリクエル", artist: "Omoinotake"),CellInfo(albumImage: "pic22", songName: "Bad Habits", artist: "Ed Sheeran")]
然後將剛剛的兩段程式改成如下:
override func numberOfSections(in tableView: UITableView) -> Int {// #warning Incomplete implementation, return the number of sectionsreturn 1}override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {// #warning Incomplete implementation, return the number of rowsreturn cellInfos.count}
改成 cellInfos.count
而不寫死數字的好處是,如果之後我新增或移除 cellInfos array 裡面的內容,就不用再回來改這裡了。
再來呢,除了這兩段程式碼,你可以看到一對 Apple 幫你寫的註解,看到這裡覺得 Apple 真的是 so sweet! 他把一些我們可能常用到的程式都寫好了,我們只要把其中一段前後的註解符號拿掉就可以直接用了!484 hen 棒!
今天用到的程式碼是下面這段,把這整段的前後註解先拿掉~
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {}
再來記錄一下我裡面寫的 code 如下:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {guard let cell = tableView.dequeueReusableCell(withIdentifier: "\(AppleMusicTableViewCell.self)", for: indexPath) as? AppleMusicTableViewCell else {return UITableViewCell()}let cellInfo = cellInfos[indexPath.row]cell.albumImageView.image = UIImage(named: cellInfo.albumImage)cell.songNameLabel.text = cellInfo.songNamecell.artistLabel.text = cellInfo.artist// Configure the cell...return cell}
這裡有一個彼得大大提到的重點:
guard let
: 這個用法有點像if let
,用來確保我的 cell 有順利產生,且成功轉型成我所指定的 AppleMusicTableViewCell ,否則就 return 一個空的 UITableViewCell()
還有一個也是很容易忘記的地方,就是要記得改 Identifier,上圖兩處紅色框框一定要對得起來,不然是生不出正確的 cell 來的。
到這邊應該就差不多囉~
Free talk
這次因為就設計單一頁面,沒有其他分頁,所以 Tab bar 也只有一頁可以選, Navigation bar 也沒有 back 按鍵囉~