iOS 17中TextField忽略Binding的getter值,如何强制其生效?
解决iOS 17中TextField不遵守Binding getter规则的问题
问题1:自定义Binding的TextField显示不更新
iOS 17中TextField内部逻辑发生变更,会优先使用自身输入缓存而非Binding getter的返回值,导致你遇到的“getter调用正常但显示不变”的问题。以下两种方案可解决:
方法1:用@State作为中间代理层
引入临时@State变量同步原始Binding的值,通过双onChange分别处理原始值变更同步和输入过滤逻辑:
@Binding var userPhoneNumber: String @State private var tempPhone: String = "" var body: some View { TextField("", text: $tempPhone) .onChange(of: userPhoneNumber) { newValue in tempPhone = newValue } .onChange(of: tempPhone) { newValue in let containsOnlyDigits = newValue.allSatisfy("0123456789".contains) guard containsOnlyDigits else { // 过滤非法字符后重置临时变量为原始有效值 tempPhone = userPhoneNumber return } userPhoneNumber = newValue } }
方法2:手动触发视图刷新
将逻辑迁移至遵循ObservableObject的ViewModel中,在过滤非法输入时手动发送变更通知,强制视图读取getter的最新值:
class PhoneViewModel: ObservableObject { @Binding var userPhoneNumber: String init(userPhoneNumber: Binding<String>) { self._userPhoneNumber = userPhoneNumber } var phoneBinding: Binding<String> { Binding(get: { self.userPhoneNumber }, set: { value in let containsOnlyDigits = value.allSatisfy("0123456789".contains) guard containsOnlyDigits else { // 手动发送变更通知,触发视图刷新 self.objectWillChange.send() return } self.userPhoneNumber = value }) } } // 视图中使用 struct PhoneInputView: View { @Binding var userPhoneNumber: String @StateObject private var viewModel: PhoneViewModel init(userPhoneNumber: Binding<String>) { self._userPhoneNumber = userPhoneNumber self._viewModel = StateObject(wrappedValue: PhoneViewModel(userPhoneNumber: userPhoneNumber)) } var body: some View { TextField("", text: viewModel.phoneBinding) } }
问题2:iOS 17中.constant绑定的TextField可被修改
iOS 17取消了.constant绑定对TextField的自动禁用逻辑,可通过以下方式恢复iOS 16的行为:
方法1:直接禁用TextField
添加.disabled(true)修饰符阻止用户输入:
struct ContentView: View { private let value: Binding<String> = .constant("1") var body: some View { VStack { TextField("", text: value) .disabled(true) } } }
方法2:自定义Binding空实现set
若需保持TextField可交互但不允许修改值,自定义Binding的set方法为空:
struct ContentView: View { private let constantValue = "1" private var value: Binding<String> { Binding(get: { constantValue }, set: { _ in }) } var body: some View { VStack { TextField("", text: value) } } }
内容的提问来源于stack exchange,提问作者Fawkes
相关产品推荐
相关产品推荐

