SwiftUI中如何实现每日零点自动重新启用习惯追踪按钮?
解决方案:基于日期持久化实现按钮每日自动启用
核心思路是通过持久化记录最后完成日期,而非单纯存储按钮禁用状态,结合日期判断自动控制按钮可用性,同时监听App状态变化确保UI实时更新。
步骤1:添加日期工具扩展
先定义一个日期扩展,用于判断两个日期是否为同一天:
import SwiftUI extension Date { func isSameDay(as date: Date) -> Bool { Calendar.current.isDate(self, inSameDayAs: date) } }
步骤2:重构按钮视图
替换原有的@State变量,改用@AppStorage持久化存储最后完成日期,通过计算属性动态判断按钮状态,同时合并重复的Button代码:
struct HabitButton: View { // 持久化存储最后完成任务的日期 @AppStorage("lastCompletionDate") private var lastCompletionDate: Date? @AppStorage("streak") private var streak: Int = 0 // 动态计算按钮是否禁用:如果今日已完成则禁用 private var isButtonDisabled: Bool { guard let lastDate = lastCompletionDate else { return false } return lastDate.isSameDay(as: Date()) } var body: some View { Button { UNUserNotificationCenter.current().setBadgeCount(0) lastCompletionDate = Date() updateStreak() } label: { Text("I have eaten an apple") .padding(.vertical, 20) .foregroundStyle(.white) .fontDesign(.rounded) .bold() .frame(width: 400) } .background(BasicColor.tint) .clipShape(RoundedRectangle(cornerRadius: 20)) .disabled(isButtonDisabled) // App从后台回到前台时,强制刷新状态 .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in objectWillChange.send() } // 视图出现时检查是否跨天 .onAppear { checkAndResetIfNewDay() } } // 习惯连续天数更新逻辑(可根据需求调整) private func updateStreak() { guard let lastDate = lastCompletionDate else { streak = 1 return } let calendar = Calendar.current guard let yesterday = calendar.date(byAdding: .day, value: -1, to: Date()) else { return } if lastDate.isSameDay(as: yesterday) { streak += 1 } else if !lastDate.isSameDay(as: Date()) { streak = 1 } // 同一天重复点击不改变连续天数 } // 检查是否跨天,可扩展通知等逻辑 private func checkAndResetIfNewDay() { guard let lastDate = lastCompletionDate else { return } if !lastDate.isSameDay(as: Date()) { // 可选:发送每日提醒通知等操作 } } } #Preview { HabitButton() }
关键改进说明
- 状态持久化:用
@AppStorage存储lastCompletionDate,避免App重启后丢失状态。 - 动态状态判断:
isButtonDisabled作为计算属性,实时对比当前日期与最后完成日期,无需手动修改状态,零点后自动启用按钮。 - 减少重复代码:合并两个重复的Button,仅通过
.disabled()修饰符控制可用性。 - App状态监听:通过
willEnterForegroundNotification确保App从后台返回时,状态能实时更新。
内容的提问来源于stack exchange,提问作者Fabio Pohl
相关产品推荐
相关产品推荐

