#7 實作表格|驚恐系列電影_TableViewController with Dynamic Prototypes

Yeh
彼得潘的 Swift iOS / Flutter App 開發教室
11 min readOct 1, 2022

【iOS 從零開始寫 #6】

表格是iOS最重要的課題之一,而製作表格的方式有很多,使用Table View Controller或View Controller + Table View等來呈現,Cell的內容也有不同的選擇(靜態&動態),這些都需要大量的練習來熟悉不同的方法。

這次先用Table View Controller加上動態表格練習多個section,來製作我喜歡的電影們 🎥,希望能對表格的喜歡多一點XD

功能應用

◼ Auto Layout (Priority設定)

◼ IBASegueAction (傳遞資料)

◼ WebKit (顯示網頁)

◼ Header (section樣式設定)

◼ NavigationItem (Navigation Bar & Tool Bar設定)

Auto Layout

  1. 將chName與release設stack view讓他們水平並排

「Priority NOTE」
在多個元件並排時,可能會因為字串太長發生螢幕寬度不足的狀況,導致label內的文字無法顯示完全,此時要透過Priority來解決:

Content Hugging Priority :數字越大越晚被拉伸。
Content Compression Resistance Priority :數字越大越晚被壓縮。

以此次製作的電影列表當例子 ⬇

調降release的Content Hugging Priority數值:在寬度足夠的情況,release寬度會被拉長,讓chName能根據文字長度固定寬度,不受空間影響,透過此設定,release可貼在chName右側。

調降chName的Content Compression Resistance Priority的數值,在寬度不足的情況,chName寬度會被壓縮,讓release可固定寬度。

但是!這樣的做法會讓chName不能完整顯示,設定chName的Autoshrink為Minimum Font Size,讓文字依據label調整字體大小,就可以看到完整的電影名稱囉~

2. enName與上個stack再設為stack垂直排列,設定向左靠齊leading。

3. 將圖片及label全部包起來,為一個stack水平並排,設定First Baseline。

Swift 程式碼

「Table NOTE」以Cell的內容分類:

⚉ 靜態 static cell:
a. 只有table view controller能使用。
b. 可直接在storyboard設計畫面進行排版,不需寫程式。
c. 可固定顯示格數,適合用在少量且確定格數的地方。

⚉ 動態 dynamic prototypes:
a. 不限定只能由table view controller使用。
b. 可直接用預設內容或透過storyboard排版,但必須用程式去顯示。
c. 適合用在顯示很多儲存格及不確定數量的時候。

Table View Controller with Dynamic Prototypes

這次製作電影列表,使用的是客製化的動態表格,利用storyboard排版。

1. 拉table view controller→建立table view controller及table view cell 類別

「補充」
Table View Controller
內容已包含table view及table view cell,且遵從UITableViewDataSource(顯示畫面) &UITableViewDelegate(觸發元件),不需自己設定。
View Controller
不包含表格相關內容及協定,需要自己設定,但在客製化有更大的彈性,能製作更多樣化的表格。

2. table view cell設定ID,style選擇custom

並將顯示在表格上的元件拉outlet在table view cell

class MovieTableViewCell: UITableViewCell {
@IBOutlet weak var pic: UIImageView!
@IBOutlet weak var chNameLbl: UILabel!
@IBOutlet weak var enNameLbl: UILabel!
@IBOutlet weak var releaseDateLbl: UILabel!
}

3. 製作表格 → 實作協定UITableViewDataSource的function「三階段對話」

👉 表格有幾段

override func numberOfSections(in tableView: UITableView) -> Int {
return movies.count
}

👉 每段表格有幾列

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let movie = movies[section].film
return movie.count
}

👉 準備每一個位置的儲存格

以儲存格ID準備儲存格(dequeue佇列),回傳一個重複使用的儲存格給指定的reuseID並加進表格。

利用as!或as?轉型成cell的型別來存取outlet,設定要顯示在儲存格的內容。

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//以儲存格ID來準備儲存格,並轉型成cell
guard let cell = tableView.dequeueReusableCell(withIdentifier:
"\(MovieTableViewCell.reuseIdentifier)", for: indexPath) as?
MovieTableViewCell
else{
//若cell沒有呼叫成功,fatalError會讓app死掉
fatalError("dequeueReusableCell failed")
}
let movie = movies[indexPath.section].film[indexPath.row]
cell.pic.image = UIImage(named: movie.pic)
cell.chNameLbl.text = movie.chName
cell.enNameLbl.text = movie.enName
cell.releaseDateLbl.text = movie.releaseDate

return cell
}

多個section的資料

關於多個section的資料,建議研究Apple官方提供的範例 Meal Tracker👇

另外,section的標題還可使用enum,會讓程式碼更乾淨喔!

IBASegueAction傳遞資料,下頁顯示WebKit網頁

先在顯示網頁的頁面(終點)宣告儲存前一頁資料的屬性

var film:Film!

由table view cell拉segue至顯示網頁的頁面

由選擇性綁定獲取被點選的儲存格section/row,在第一頁(起點)透過segue拉IBSegueAction,將該儲存格的資料傳至下一頁

@IBSegueAction func showTrailer(_ coder: NSCoder) -> YoutubeViewController? {
//透過選擇性綁定得到被點選的儲存格section/row
if let section = tableView.indexPathForSelectedRow?.section,
let row = tableView.indexPathForSelectedRow?.row{
let youtubeVC = YoutubeViewController(coder: coder)
youtubeVC?.film = movies[section].film[row]
return youtubeVC
}
return nil
}

使用webkit播放youtube

import WebKit
@IBOutlet weak var webkitView: WKWebView!
//使用webkit播放youtube
if let url = URL(string: "https://www.youtube.com/watch?v=\
(self.film.trailer)"){
print("url right")
let request = URLRequest(url: url)
self.webkitView.load(request)
}

App實際操作

遇到的問題

WebKit顯示網頁會出現與執行緒相關的紫色錯誤,似乎是更新版本後出現的問題,谷歌後發現很多人發生相同狀況,但尚未有解決方法,彼得說暫時不影響運作,還是可以使用~

Auto Layout還不是很熟悉,有時調整好了,換型號顯示卻跑出紅色錯誤,但有時調整完成,卻不知道怎麼設定的??? 努力中 💪 💪 💪

--

--