大家好,鐵人賽堂堂邁入第二十四日!
昨天,我們精心設計了聊天畫面的最小單位——MainTableViewCell
。今天,我們的任務是將這些獨立的氣泡組裝起來,搭建出一個大家所熟悉的、可以上下滾動的聊天主介面。我們將使用 iOS 開發中最核心的元件之一:UITableView
。
MainViewController.xib
)首先,我們來設計主畫面的外觀。在 Xcode 中打開 MainViewController.xib
,並從元件庫中拖拉以下三個核心元件到畫面上:
UITableView
(聊天列表): 佔據畫面的大部分空間,用來顯示我們的聊天氣泡。UITextField
(訊息輸入框): 放置在畫面底部,讓使用者可以輸入文字。UIButton
(發送按鈕): 放置在輸入框旁邊。完成後,使用 @IBOutlet
將這三個元件連接到 MainViewController.swift
檔案中。
// MainViewController.swift
import UIKit
class MainViewController: UIViewController {
@IBOutlet weak var tbvChat: UITableView!
@IBOutlet weak var btnSend: UIButton!
@IBOutlet weak var txfMessage: UITextField!
// 用一個陣列來儲存所有的對話訊息
var messages: [Message] = []
// ...
}
光有介面是不夠的,我們需要用程式碼告訴 UITableView
該如何顯示資料。這個過程主要透過兩個重要的代理 (Protocol) 來完成:UITableViewDataSource
和 UITableViewDelegate
。
在 MainViewController.swift
的 viewDidLoad
方法中,我們進行初步設定:
// MainViewController.swift
func setupTbv() {
// 1. 註冊我們昨天設計的 Cell XIB
tbvChat.register(UINib(nibName: "MainTableViewCell", bundle: nil), forCellReuseIdentifier: MainTableViewCell.identifile)
// 2. 設定代理
tbvChat.dataSource = self
tbvChat.delegate = self
// 3. UI 優化
tbvChat.separatorStyle = .none // 隱藏 Cell 之間的分隔線
}
接著,我們讓 MainViewController
遵循這兩個代理,並實現最核心的兩個方法:
// MainViewController.swift
// 讓 ViewController 遵循 UITableViewDataSource 和 UITableViewDelegate
extension MainViewController: UITableViewDelegate, UITableViewDataSource {
// 方法一:告訴 TableView 有多少行
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return messages.count // 行數等於我們訊息陣列的數量
}
// 方法二:告訴 TableView 每一行該長什麼樣子
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// 1. 從重用池中取出我們自訂的 Cell
let cell = tableView.dequeueReusableCell(withIdentifier: MainTableViewCell.identifile, for: indexPath) as! MainTableViewCell
// 2. 取得對應的訊息資料
let message = messages[indexPath.row]
// 3. 呼叫我們昨天寫的 configure 方法,讓 Cell 自己更新外觀
cell.configure(with: message)
return cell
}
}
為了在連接 API 之前先驗證我們的 UI 是否正常,我們先在 MainViewController
中加入一個 loadInitialMessages
函式,用來載入一些「假資料」。
// MainViewController.swift
func loadInitialMessages() {
// 建立幾筆測試訊息
messages = [
Message(text: "你好!我可以幫你查詢伺服器資安事件。", sender: .bot),
Message(text: "查詢最近的資安事件", sender: .user),
Message(text: "好的,以下是最近的資安事件:...", sender: .bot)
]
// 重新載入 TableView 讓畫面更新
tbvChat.reloadData()
}
最後,在 viewDidLoad
中呼叫 loadInitialMessages()
。現在,運行你的 App,你將會看到一個漂亮的、包含三則對話的聊天畫面並且傳送一個訊息出去,把回覆設定成hi,如下圖:
可以看到我們的訊息成功送出囉!!
今天,我們成功地將獨立的聊天氣泡,組裝成一個完整的聊天主畫面。我們學會了:
UITableView
,並將其與資料來源連接。
UITableViewDataSource
的核心方法,動態地產生 Cell。
我們的 App 現在已經「有形有樣」了。明天,我們將進入最激動人心的環節——我們會將 UI 與 NetworkManager
連接起來,發送第一筆真實的 API 請求,並將後端 Agent 的回覆,動態地顯示在畫面上!