iT邦幫忙

2025 iThome 鐵人賽

DAY 25
0

TableView 的結構與行為

TableView 的設計非常精簡,每一列代表一個設定項目,共四列:

  • 重複:設定哪些天要響。
  • 標籤:自訂鬧鐘名稱。
  • 提示聲:選擇音效。
  • 稍後提醒:是否開啟 Snooze。

我們在 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 的整體設計與互動邏輯。


上一篇
Day 24 時鐘 3
下一篇
Day 26 時鐘 5
系列文
Swift一下就會了27
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言