SwiftUI自定义倒计时DatePicker首次启动默认1分钟问题咨询
问题根源
UIDatePicker的.countDownTimer模式存在系统默认行为:控件初始化完成后如果没有在makeUIView阶段显式设置初始countDownDuration值,第一次用户滚动选择器修改时长时,.valueChanged事件不会触发,也就不会同步修改绑定的duration值,此时duration还是初始的60.0,所以首次启动会按1分钟倒计时。第二次调整时长时控件初始化流程已完成,事件可以正常触发,值同步也就生效了。
修复步骤
只需要在DurationPicker的makeUIView方法中,创建UIDatePicker后主动设置初始时长即可,修改后的代码如下:
import SwiftUI struct DurationPicker: UIViewRepresentable { @Binding var duration: Double func makeUIView(context: Context) -> UIDatePicker { let datePicker = UIDatePicker() datePicker.datePickerMode = .countDownTimer // 新增:初始化时就设置初始时长,解决首次修改不触发事件的问题 datePicker.countDownDuration = duration datePicker.addTarget(context.coordinator, action: #selector(Coordinator.updateDuration), for: .valueChanged) return datePicker } func updateUIView(_ datePicker: UIDatePicker, context: Context) { // 新增判断:避免不必要的重复赋值,防止循环触发更新 if datePicker.countDownDuration != duration { datePicker.countDownDuration = duration } } func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject { let parent: DurationPicker init(_ parent: DurationPicker) { self.parent = parent } @objc func updateDuration(datePicker: UIDatePicker) { parent.duration = datePicker.countDownDuration } } } struct ContentView: View { @State var duration = 60.0 @State var timeRemaining = 60.0 @State private var isActive = false let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect() var body: some View { VStack { Text("\(timeRemaining)") .bold() .font(.largeTitle) DurationPicker(duration: $duration) HStack { Button("Cancel") { isActive = false } .padding() Button("Start") { self.timeRemaining = duration isActive = true } .padding() } } .onReceive(timer) { time in guard self.isActive else { return } if self.timeRemaining > 0 { self.timeRemaining -= 1 } } .onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in self.isActive = false } .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in self.isActive = true } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
额外注意事项
UIDatePicker的countDownDuration要求值必须是60的整数倍,系统会自动对非60倍数的数值做取整处理,建议给duration赋值时保证符合该规则,避免出现UI和绑定值不一致的问题。- 原代码中的
timer属性建议改为let,因为不需要修改它的实例,符合Swift语法规范。
内容的提问来源于stack exchange,提问作者Sebastian Banks
相关产品推荐
相关产品推荐

