自定义View中@Binding变量与TextField内容不同步的原因?
问题描述
在自定义View组件中使用@Binding绑定TextField时遇到异常:用户输入的内容无法同步到ContentView的text变量中,导致弹窗(sheet)显示为空。但只要在ContentView中添加Text(text)控件,或者使用自定义Binding传递给Input View,数据同步就恢复正常。
初始ContentView代码
struct ContentView: View { @State private var text = "" @State private var present = false var body: some View { VStack { Input(text: $text) Button("Submit") { present = true } } .sheet(isPresented: $present) { Text(text) } } } struct Input: View { @Binding var text: String var body: some View { TextField("hint", text: $text) } }
添加Text后的ContentView代码
struct ContentView: View { @State private var text = "" @State private var present = false var body: some View { VStack { // ADDED Text(text) .font(.title) Input(text: $text) Button("Submit") { present = true } } .sheet(isPresented: $present) { Text(text) } } }
使用自定义Binding的代码
struct ContentView: View { @State private var text = "" @State private var present = false var body: some View { VStack { // Custom Binding Input(text: .init(get: { text }, set: { text = $0 })) Button("Submit") { present = true } } .sheet(isPresented: $present) { Text(text) } } }
原因分析
这是SwiftUI的视图更新依赖追踪机制导致的:
- SwiftUI只会重新计算那些依赖了变化状态的视图部分。初始代码中,
ContentView的body仅将$text绑定传递给子视图Input,自身没有直接读取text的值,因此SwiftUI的依赖追踪没有把text标记为ContentView的依赖项。 - 当用户在
TextField输入时,text的底层值确实被修改,但ContentView的body不会触发重新计算,弹窗捕获的还是旧的text值。 - 添加
Text(text)后,ContentView的body直接读取了text,SwiftUI会将text纳入ContentView的依赖列表,text变化时会触发ContentView重新计算,弹窗就能拿到最新值。 - 使用自定义
Binding时,set闭包直接在ContentView的上下文内修改text,强制SwiftUI检测到text变化与ContentView的关联,进而触发视图更新。
内容的提问来源于stack exchange,提问作者Toru
相关产品推荐
相关产品推荐

