SwiftUI中TextField无法自动更新计时内容的问题求助
解决SwiftUI中TextField实时更新计时器的问题
嘿,我来帮你搞定这个TextField不更新的问题~
问题根源
你当前的代码里,TextField绑定的是@State变量time,但只有在点击Start按钮时才给time赋值了一次,后续Timer触发更新min和sec的时候,并没有同步更新time——这就是TextField不跟着变化的核心原因。而Text组件如果直接使用min和sec的话,因为这两个是@State变量,变化时会触发视图更新,所以能正常显示。
修复方案1:实时更新time变量
直接在Timer的回调里同步更新time,让绑定的TextField能感知到变化。同时注意你之前的秒数判断逻辑有点小问题(应该是sec等于60时进分钟,而不是59),一起修正:
import SwiftUI struct ContentView: View { @State var min: Int = 0 @State var sec: Int = 0 @State var time = "" @State var timer: Timer? = nil var body: some View { NavigationView{ VStack{ TextField("Tempo (min o mm:ss)", text: $time) HStack{ Button(action: { self.start() // 这里可以删掉,因为Timer第一次触发会自动更新time // self.time = String(self.min)+":"+String(self.sec) }){ Text("Start") } Button(action: { self.stop() }){ Text("Stop") } } } } } func start(){ timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true){ temp in self.sec += 1 if self.sec == 60 { // 修正:秒数到60才进分钟 self.sec = 0 self.min += 1 } // 关键:每次计时更新时同步修改time变量 self.time = String(format: "%02d:%02d", self.min, self.sec) } } func stop(){ timer?.invalidate() timer = nil } }
修复方案2:用计算属性替代手动维护time(更优雅,适合仅显示场景)
如果你的TextField只用来显示计时、不需要用户编辑的话,可以把time改成计算属性,不用手动维护,直接由min和sec推导而来:
import SwiftUI struct ContentView: View { @State var min: Int = 0 @State var sec: Int = 0 @State var timer: Timer? = nil // 计算属性,自动根据min和sec生成格式化字符串 var time: String { String(format: "%02d:%02d", min, sec) } var body: some View { NavigationView{ VStack{ // 用.constant绑定计算属性,因为计算属性不能直接双向绑定 TextField("Tempo (min o mm:ss)", text: .constant(time)) HStack{ Button(action: { self.start() }){ Text("Start") } Button(action: { self.stop() }){ Text("Stop") } } } } } func start(){ timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true){ temp in self.sec += 1 if self.sec == 60 { self.sec = 0 self.min += 1 } } } func stop(){ timer?.invalidate() timer = nil } }
进阶优化:使用SwiftUI原生的Timer发布者
Foundation的Timer有时候会因为RunLoop模式的问题(比如界面滚动时暂停),更推荐用SwiftUI的Timer.publish结合Combine框架,更贴合响应式编程风格:
import SwiftUI import Combine struct ContentView: View { @State var min: Int = 0 @State var sec: Int = 0 @State var time = "" // 用Combine的Cancellable管理Timer @State private var timerCancellable: Cancellable? = nil var body: some View { NavigationView{ VStack{ TextField("Tempo (min o mm:ss)", text: $time) HStack{ Button(action: { self.start() }){ Text("Start") } Button(action: { self.stop() }){ Text("Stop") } } } } } func start(){ // 创建主队列的Timer发布者,自动连接并订阅 timerCancellable = Timer.publish(every: 1, on: .main, in: .common) .autoconnect() .sink { _ in self.sec += 1 if self.sec == 60 { self.sec = 0 self.min += 1 } self.time = String(format: "%02d:%02d", self.min, self.sec) } } func stop(){ timerCancellable?.cancel() timerCancellable = nil } }
内容的提问来源于stack exchange,提问作者Aniello Baldi
相关产品推荐
相关产品推荐

