TableView 的設計非常精簡,每一列代表一個設定項目,共四列:
我們在 cellForRowAt 裡根據 index 設定每列的內容與行為:
extension AddAlarmViewController: UITableViewDelegate, UITableViewDataSource {
// 設定tableView有幾個section
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 4 }
// 設定每個section裡有多少row
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "AddAlarmTableViewCell", for: indexPath) as! AddAlarmTableViewCell
cell.lbAddAlarm.isHidden = false
cell.txfRename.isHidden = true
cell.lbPushToRepoeat.isHidden = true
cell.lbPushToSound.isHidden = true
cell.swAddAlarm.isHidden = true
cell.accessoryType = .none
cell.txfRename?.placeholder = "鬧鐘"
switch indexPath.row {
case 0: // 重複
cell.lbAddAlarm.text = "重複"
cell.lbPushToRepoeat.isHidden = false
let daysOfWeek = ["週日", "週一", "週二", "週三", "週四", "週五", "週六"]
let selectedDays = repeatDays.enumerated().filter { $0.1 }.map { $0.0 }
let repeatTitle: String
if selectedDays.count == 2 && selectedDays.contains(0) && selectedDays.contains(6) {
repeatTitle = "假日 "
} else if selectedDays.count == 5 && selectedDays == [1,2,3,4,5] {
repeatTitle = "平日 "
} else if selectedDays.count == 0 {
repeatTitle = "永不 "
} else if selectedDays.count == 7 {
repeatTitle = "每天"
} else {
let selectedNames = selectedDays.map { daysOfWeek[$0] }
repeatTitle = "\(selectedNames.joined(separator: "、")) "
}
cell.lbPushToRepoeat.text = repeatTitle
cell.accessoryType = .disclosureIndicator
case 1: // 標籤
cell.lbAddAlarm.text = "標籤"
cell.txfRename.isHidden = false
cell.txfRename.text = alarmname
cell.txfRename.delegate = self
cell.txfRename.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
case 2: // 提示聲
cell.lbAddAlarm.text = "提示聲"
cell.lbPushToSound.isHidden = false
let soundTitle = selectedSound.isEmpty ? "預設提示聲 " : "\(selectedSound) "
cell.lbPushToSound.text = soundTitle
cell.accessoryType = .disclosureIndicator
case 3: // 稍後提醒
cell.lbAddAlarm.text = "稍後提醒"
cell.swAddAlarm.isHidden = false
cell.swAddAlarm.isOn = snoozeEnabled
cell.swAddAlarm.addTarget(self, action: #selector(snoozeSwitchChanged(_:)), for: .valueChanged)
default: break
}
return cell
}
每當使用者點擊某一列時,TableView
都會觸發 didSelectRowAt
。
我們根據點擊的項目,執行對應的操作,例如跳轉設定頁面或切換開關:
// 根據點擊的cell類型,執行不同的操作
// 點擊重複、標籤或提示聲時,會跳轉到對應的設定頁面
// 點擊稍後提醒時,會切換開關狀態
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
switch indexPath.row {
case 0:
repeatButtonTapped() // 點擊「重複」直接跳頁
case 1:
if let cell = tableView.cellForRow(at: indexPath) as? AddAlarmTableViewCell {
cell.txfRename.becomeFirstResponder()
}
case 2:
soundButtonTapped()
default:
break
}
}
也設定了每列的固定高度與名稱更新方法:
// 設定cell的高度為56行
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 56 }
// 更新鬧鐘名稱
func updateAlarmName(from textField: UITextField?) {
alarmname = textField?.text ?? "鬧鐘"
}
}
我們使用 Delegate
模式讓其他頁面能夠回傳資料給主畫面:
// 當使用者在鬧鐘名稱輸入框結束編輯時,會更新鬧鐘名稱
extension AddAlarmViewController {
func textFieldDidEndEditing(_ textField: UITextField) {
alarmname = textField.text ?? "鬧鐘"
}
}
// 當使用者在提示聲頁面選擇了提示聲後,會回傳選擇的提示聲
extension AddAlarmViewController: SoundViewControllerDelegate {
func didSelectSound(_ sound: String) {
selectedSound = sound
tbvAddAlarm.reloadData()
}
}
// 當使用者在重複頁面選擇了重複天數後,會回傳選擇的天數
extension AddAlarmViewController: RepeatViewControllerDelegate {
func didUpdateRepeatDays(_ days: [Bool]) {
repeatDays = days
tbvAddAlarm.reloadData()
}
}
這樣使用者在其他頁面更改設定後,回到主頁時畫面就會即時更新。
今天我們完成了鬧鐘設定畫面中 TableView
的整體設計與互動邏輯。