SwiftUI实现新日期到来时自动更新按钮颜色(应用运行时生效)
解决按钮跨天自动更新颜色的问题
你的代码目前存在两个核心问题:
- 直接读取UserDefaults不会触发视图刷新,即使日期跨天,按钮颜色也不会自动变化
- 应用运行期间无法感知新一天的到来,无法主动更新视图状态
以下是修改后的完整代码,解决了上述问题:
import SwiftUI import Combine struct ButtonView: View { @Binding var streak: Int // 使用@AppStorage自动同步UserDefaults并触发视图刷新 @AppStorage("lastUserDate") private var lastUserDate: Date? // 定时器相关,用于监听新一天的到来 @State private var dateTimer: Timer.TimerPublisher? @State private var cancellable: AnyCancellable? private var canUserPress: Bool { guard let lastDate = lastUserDate else { return true } return !Calendar.current.isDateInToday(lastDate) } private var buttonColor: LinearGradient { canUserPress ? LinearGradient(gradient: Gradient(colors: [.black, .green]), startPoint: .leading, endPoint: .trailing) : LinearGradient(gradient: Gradient(colors: [.black, .purple]), startPoint: .leading, endPoint: .trailing) } var body: some View { Button { guard canUserPress else { return } lastUserDate = Date() streak += 1 } label: { ZStack { Circle() .fill(buttonColor) .frame(width: 200, height: 200) Text("Add!") .bold() .font(.title) .foregroundColor(.white) } } .onAppear { startDateTimer() } .onDisappear { cancellable?.cancel() } } // 设置定时器,在新一天到来时触发视图刷新 private func startDateTimer() { cancellable?.cancel() // 计算下一次午夜的时间点 guard let nextMidnight = Calendar.current.nextDate( after: Date(), matching: DateComponents(hour: 0, minute: 0, second: 0), matchingPolicy: .nextTime ) else { // 计算失败时,每秒检查一次(兜底方案) dateTimer = Timer.publish(every: 1, on: .main, in: .common) cancellable = dateTimer?.autoconnect().sink { _ in objectWillChange.send() } return } // 设置定时器到午夜触发,触发后重新设置下一天的定时器 let interval = nextMidnight.timeIntervalSince(Date()) dateTimer = Timer.publish(every: interval, on: .main, in: .common) cancellable = dateTimer?.autoconnect().sink { _ in objectWillChange.send() startDateTimer() } } } struct ButtonView_Previews: PreviewProvider { static var previews: some View { ButtonView(streak: .constant(0)) } }
关键修改说明:
@AppStorage替代手动UserDefaults操作:
自动同步lastUserDate和UserDefaults,当值变化时会自动触发视图刷新,无需手动处理数据同步和刷新逻辑。添加跨天监听定时器:
- 计算下一次午夜的时间,设置精准定时器,到点后触发视图刷新,确保新一天到来时按钮颜色自动更新
- 定时器触发后会重新计算下一次午夜时间,循环监听后续的日期变化
- 加入兜底方案,避免日期计算失败时无法刷新视图
简化逻辑:
移除了冗余的@State lastUserDate,简化canUserPress的判断逻辑,让代码更清晰易维护
内容的提问来源于stack exchange,提问作者Nikita Kolomoec
相关产品推荐
相关产品推荐

