iT邦幫忙

2025 iThome 鐵人賽

DAY 22
0

今天開始,我們要進入下一個有趣的主題時鐘

先來看看成果:
https://ithelp.ithome.com.tw/upload/images/20251006/20178746B6p34z5Pfg.png

鬧鐘資料更新

這裡我們透過 Delegate 來傳遞事件,每當資料有變化,就重新載入並刷新 TableView

// MARK: - Delegate
    // 當新增鬧鐘後,重新載入資料
    func didAddNewAlarm() {
        loadAlarms()
        tbvData.reloadData()
    }
    // 當編輯鬧鐘後,重新載入資料
    func didUpdateAlarm() {
        loadAlarms()
        tbvData.reloadData()
    }
    // 當刪除鬧鐘後,重新載入資料
    func didDeleteAlarm() {
        loadAlarms()
        tbvData.reloadData()
    }
    // 當點選鬧鐘音效頁面後,回傳選擇的音效名稱
    func didTapPushToSound() {
        let soundVC = SoundViewController()
        soundVC.delegate = self
        navigationController?.pushViewController(soundVC, animated: true)
    }

Tips:每一次的操作,都要確保 UI 和資料保持同步,否則列表就會和實際的鬧鐘設定脫節

連接 TableView

我們在 Storyboard 裡放入一個 UITableView 來顯示所有鬧鐘,並透過 IBOutlet 與程式碼連接。
接下來只要設定好 DataSourceDelegate,就能讓資料跑進這個表格中。

    // MARK: - IBOutlet
    @IBOutlet weak var tbvData: UITableView!

載入與通知監聽

viewDidLoad() 中,我們要做幾件重要的事:
設定 UINavigation Bar
請求通知權限。
監聽鬧鐘觸發的通知。
載入現有鬧鐘資料。

    // MARK: - LifeCycle
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setUI()
        setupNavigationBar()
        requestNotificationPermission()
        // 載入鬧鐘資料
        NotificationCenter.default.addObserver(self, selector: #selector(showAlarmAlert(_:)), name: NSNotification.Name("AlarmDidFire"), object: nil)
        loadAlarms()
        tbvData.reloadData()
        
        }

UI 設定與按鈕動作

我們把 Navigation Bar的設定做好,上面有「新增」和「編輯」按鈕:

// MARK: - UI Setting
    func setupNavigationBar() {
        navigationController?.navigationBar.barTintColor = .systemGray6
        // 利用UIImage設定右邊的按鈕為加號的圖案,讓後設定他的動作為`addTapped`的function
        navigationItem.rightBarButtonItem =
        UIBarButtonItem(image: UIImage(systemName: "plus"),
                                        style: .plain,
                                        target: self,
                                        action: #selector(addTapped))
        // 左邊按鈕則是用title設定他的文字為編輯,並設定他的動作為`editTapped`
        navigationItem.leftBarButtonItem =
        UIBarButtonItem(title: "編輯",
                        style: .plain,
                        target: self,
                        action: #selector(editTapped))
        // 設定成我誠品畫面中的那樣,並且當中間tableView存放鬧鐘的地方往上滑動時,他會變為在左右 Button 的中間
        navigationController?.navigationBar.prefersLargeTitles = true
        // 然後再設定我們需要他顯示什麼字,比如我們設定的字為鬧鐘
        navigationItem.title = "鬧鐘"
    }
    func setUI() {
        tbvData.dataSource = self
        tbvData.delegate = self
        tbvData?.register(UINib(nibName: "MainTableViewCell", bundle: nil),forCellReuseIdentifier: "MainTableViewCell")
    }

請求通知權限

鬧鐘要能夠在背景提醒使用者,就必須向系統請求推播權限:

    //請求通知權限
    func requestNotificationPermission() {
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
            // 請求成功印出成功獲取
            if granted {
                print("Notification permission granted")
                
            // 請求失敗印出獲取失敗
            } else {
                print("Notification permission denied")
            }
        }
    }

主要動作與事件處理

以下幾個方法處理了新增鬧鐘、編輯模式切換,以及鬧鐘響起時的提示:

// MARK: - IBAcion
    // 當點選右上角的加號按鈕時,會跳出新增鬧鐘的畫面
    @objc func addTapped() {
        let addAlarmVC = AddAlarmViewController()
        addAlarmVC.delegate = self
        let navController = UINavigationController(rootViewController: addAlarmVC)
        self.present(navController, animated: true)
    }
    // 首先我們要建立一個 isEditing 參數
    var isEdting: Bool = false
    // 當點選左上角的編輯按鈕時,會切換編輯模式
    @objc func editTapped() {
        isEdting.toggle()
        tbvData.setEditing(isEdting, animated: true)
        
        // 利用剛開始設定的布林參數做變動
        navigationItem.leftBarButtonItem?.title = isEdting ? "完成" : "編輯"
        
        // 遍歷所有當前可見的表格視圖單元格,並將其隱藏的開關控件設置為編輯狀態。
        tbvData.visibleCells.forEach { cell in
            if let switchControl = (cell as? MainTableViewCell)?.swTime {
                switchControl.isHidden = isEdting
            }
        }
    }
    // 當鬧鐘響起時,顯示一個警告對話框
    @objc func showAlarmAlert(_ notification: Notification) {
        print("收到 AlarmDidFire 通知")
        guard let noti = notification.object as? UNNotification else { return }
        let content = noti.request.content
        let alert = UIAlertController(title: content.title, message: content.body, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "確定", style: .default))
        present(alert, animated: true)
    }
    // 當開關切換時,更新鬧鐘的狀態
    @objc func alarmSwitchChange(_ sender: UISwitch) {
        let row = sender.tag
        let alarm = alarms[row]
        print("開關切換:第 \(row) 筆,狀態為 \(sender.isOn)")

        // 更新 Realm 中的開關狀態(如有需要)
        let realm = try! Realm()
        try! realm.write {
            alarm.isEnabled = sender.isOn
            }

    }

結語

今天我們先完成了時鐘 App的基本架構,包含導航列的設定、TableView 的資料顯示以及通知權限的請求等重要步驟。


上一篇
Day 21 留言板 6
系列文
Swift一下就會了22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言