#Task-13 實作 Table View 的基本功能 - Line 介面

模仿製作 Line 的介面來練習實作表格的基本功能和定義 UITableViewDataSource 的相關 function

最近大大小小的事情讓人心浮氣躁,也可能是天氣太熱(? 快變成失蹤人口的我終於回來繼續發文了😌

這次要實作 Table View 的基本功能,就用每天都在使用的 Line 來練習吧!

⭐️ 完成的畫面如下:

Table View 的 Content 分成 Dynamic Prototypes 跟 Static Cells 兩種, Dynamic Prototypes 適合用在內容數量不固定、數量多、內容一致或類似的表格呈現,需要透過寫程式才能顯示內容;Static Cells 比較適合已知內容數量、數量少或是需要客製化 cell 樣式的時候使用,方便視覺化編輯

例如這次 Line 的介面,首頁因為 cell 內容不多,且不同 cell 有不同的樣貌,所以使用 Static Cells 直接佈置畫面;顯示好友名單的畫面則因為大部分都是相同的格式,就使用 Dynamic Prototypes 來製作!

⭐️ 畫面佈局

💡 首頁:Table View Controller + Collection View (取名mainTableViewController)

Table View 相關設定:

  • Content:Static Cells
  • Sections:4
    其中 Section 3 是在 Cell 中加入Collection View 來製作,連結放在最後面
  • Style:Inset Group
  • Separator:None (不顯示分隔線)
畫面分成 4 個 Section

💡 好友名單畫面:Table View Controller (取名detailTableViewController)

Table View 相關設定:

  • Content:Dynamic Prototypes
  • Prototype Cells:1
  • Separator:None (不顯示分隔線)

在 Prototype Cells 上面加入一個 View,來放 Search Bar、Button、Label 等跟底下 cell 長得不一樣的元件,名單顯示則用 Prototype Cells 統一呈現

表格內容依照需求佈置畫面,畫面中的元件都有使用 Auto Layout

這次最滿意的應該是有做出跟 Line 首頁最上方的 Navigation Bar 一樣的顯示動畫部分😂 之後再寫一篇說明!

⭐️ 表格資料

💡 新增 Swift File,建立 Struct 型別

import Foundation//首頁中的CollectionView使用
struct Service{
let name: String
let image: String
}
struct Theme{
let name: String
let image: String
}
struct Sticker{
let name: String
let image: String
}
//好友頁面使用
struct TitleName{
let name: String
let number: Int
}
struct List{
let name: String
let words: String
let image: String
}

💡 在 Table View Controller 中建立假資料 Array 內容,以便呼叫資料來顯示在對應的位置

//首頁資料 
class mainTableViewController: UITableViewController {
var services = [
Service(name: "貼圖小舖", image: "icon1"),
Service(name: "主題小舖", image: "icon2"),
...

var themes = [
Theme(name: "小熊維尼(雨過天晴篇)", image: "theme1"),
Theme(name: "米奇(水彩畫風篇)", image: "theme2"),
...

var stickers = [
Sticker(name: "ㄇㄚˊ幾兔-賣萌大作戰", image: "sticker1"),
Sticker(name: "來貘,又動了", image: "sticker2"),
...
}
//好友名單資料
class detailTableViewController: UITableViewController {
var titles = [
TitleName(name: "我的最愛", number: 34),
TitleName(name: "好友", number: 524),
...

var favoriteLists = [
List(name: "Mom", words: "", image: "selfie1"),
List(name: "Brother", words: "", image: "selfie2"),
...

var friendList = [
List(name: "Angel", words: "Happy Life", image: "friend1"),
List(name: "甄", words: "", image: "friend2"),
...

var groupList = [
List(name: "建立群組", words: "與好友們建立群組聊天室吧。", image: "group1"),
List(name: "社群", words: "開團找話題,聊出新麻吉~", image: "group2"),
...
}

⭐️ 資料傳遞與顯示

💡 首頁到好友名單的資料傳遞

使用 tableView(_:didSelectRowAt:) 方法來得到使用者選擇的是哪一個 row,將數值傳到好友名單的 Table View Controller,呼叫對應的資料來顯示

Table View Controller 自動預設為 Table View 的 dataSource 跟 delegate,所以不用另外再拉 outlet,直接使用 function 即可

  • 宣告變數,後續用來儲存點選的 row 的值
var rowNum = 0
  • 從首頁的 Controller 拉 Segue 到好友名單的 Controller,點選 Segue 設定 Identifier 名稱
  • tableView(_:didSelectRowAt:)
//mainTableViewControlleroverride func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
rowNum = indexPath.row //儲存點選的row值
performSegue(withIdentifier: "detailSegue", sender: nil)
//觸發Segue顯示好友名單
}
  • 到好友名單的 Controller ,同樣宣告變數來儲存傳遞過來的值,並設定 init 取得資料
//detailTableViewControllervar row = Int()

init?(coder: NSCoder, row: Int){
self.row = row
super.init(coder: coder)
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
  • 回到首頁的 Controller 從 Segue 拉線建立 IBSegueAction function,設定要傳輸及接收的對應 property
@IBSegueAction func showDetail(_ coder: NSCoder) -> detailTableViewController? {
return detailTableViewController(coder: coder, row: rowNum)
}

💡 好友名單顯示

  • 建立 Cocoa Touch Class 的 UITableViewCell 類別,點選 Table View Cell 設定 Class 為剛剛建立好的類別,同時設定 Identifier
  • 在裡面宣告 Prototype Cells 要顯示的 property,並拉 outlet 到對應的元件
  • 設定 Table View 的 Section 跟 row 的數量

Swift 很貼心,程式碼本來就有註解在 Table View Controller 裡面,只要寫回傳的值就可以了

override func numberOfSections(in tableView: UITableView) -> Int {
return 1 //如果沒寫這段程式碼,預設的Section數量值是1
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10 //因為每個Array的假資料我都做10筆,所以回傳10
}
  • 定義型別,宣告 type property 儲存 reuse id
class detailTableViewController: UITableViewController {

struct PropertyKeys {
static let detailCell = "detailCell"
}
}
  • 使用 tableView(_:cellForRowAt:) 方法,請求 dataSource 將要顯示的資料放入對應的 cell 位置
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

//設定cell的Identifier並轉型為detailTableViewCell,以使用宣告的property
let cell = tableView.dequeueReusableCell(withIdentifier: PropertyKeys.detailCell, for: indexPath) as! detailTableViewCell

let getRowNum = row //宣告property儲存從首頁傳來的row值

//根據row的值設定對應要顯示的Array資料
if getRowNum == 1{
cell.profileImageView.image = UIImage(named: favoriteLists[indexPath.row].image)
cell.nameLabel.text = favoriteLists[indexPath.row].name
cell.wordsLabel.text = favoriteLists[indexPath.row].words
}else if getRowNum == 2{
cell.profileImageView.image = UIImage(named: friendList[indexPath.row].image)
cell.nameLabel.text = friendList[indexPath.row].name
cell.wordsLabel.text = friendList[indexPath.row].words
}else{
cell.profileImageView.image = UIImage(named: groupList[indexPath.row].image)
cell.nameLabel.text = groupList[indexPath.row].name
cell.wordsLabel.text = groupList[indexPath.row].words
}
return cell
}

這樣就完成了!

延伸閱讀

Section3 水平捲動的 Collection View

附上作業的 GitHub 連結

參考資料

--

--