升级至iOS 17.0后TextField出现无法删除最后一位数字的Bug
iOS 17 数字 TextField 无法删除最后一位的问题修复
问题判断
这确实是iOS 17 SwiftUI的已知问题之一。当使用绑定非可选数值类型(如Int/Double)配合.number格式的TextField时,由于绑定值无法被置为nil,系统处理最后一位数字删除操作时,无法正确转换空输入的逻辑,导致无法清空内容。
修复方案
以下是几种可行的修复方式,可根据你的业务场景选择:
方案1:将绑定值改为可选类型
把userViewModel.focusTime的类型从非可选数值(比如Int)改为可选类型(Int?),让系统能正确处理空输入:
// 在ViewModel中修改属性类型 var focusTime: Int? = 0 // 可根据需求初始化为nil或默认值 // TextField代码无需大幅调整 TextField("Focus Time", value: $userViewModel.focusTime, format: .number) .frame(width: 220, height: nil) .keyboardType(.numberPad) .textFieldStyle(.roundedBorder) .font(Font.system(size: 25, design: .default)) .multilineTextAlignment(TextAlignment.center) .focused($textIsFocused1) .onTapGesture { textIsFocused1.toggle() }
方案2:改用文本绑定替代数值绑定
如果不想修改ViewModel的属性类型,可以绑定String类型,手动处理字符串与数值的转换:
// 在ViewModel中新增计算属性 var focusTimeText: String { get { String(focusTime) } set { if let num = Int(newValue) { focusTime = num } else if newValue.isEmpty { focusTime = 0 // 根据需求设置空输入时的默认值 } } } // 修改TextField绑定目标 TextField("Focus Time", text: $userViewModel.focusTimeText) .frame(width: 220, height: nil) .keyboardType(.numberPad) .textFieldStyle(.roundedBorder) .font(Font.system(size: 25, design: .default)) .multilineTextAlignment(TextAlignment.center) .focused($textIsFocused1) .onTapGesture { textIsFocused1.toggle() } // 可选:限制仅能输入数字 .onChange(of: userViewModel.focusTimeText) { newValue in let filtered = newValue.filter { $0.isNumber } if filtered != newValue { userViewModel.focusTimeText = filtered } }
方案3:使用UIKit包装的TextField(兼容更稳定)
如果上述方案仍有问题,可以用UIViewRepresentable包装UIKit的UITextField,彻底规避SwiftUI的这个bug:
struct NumberTextField: UIViewRepresentable { @Binding var value: Int var placeholder: String func makeUIView(context: Context) -> UITextField { let textField = UITextField() textField.placeholder = placeholder textField.keyboardType = .numberPad textField.borderStyle = .roundedRect textField.textAlignment = .center textField.font = UIFont.systemFont(ofSize: 25) textField.delegate = context.coordinator textField.text = String(value) return textField } func updateUIView(_ uiView: UITextField, context: Context) { if uiView.text != String(value) { uiView.text = String(value) } } func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, UITextFieldDelegate { var parent: NumberTextField init(_ parent: NumberTextField) { self.parent = parent } func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let currentText = textField.text ?? "" guard let stringRange = Range(range, in: currentText) else { return false } let updatedText = currentText.replacingCharacters(in: stringRange, with: string) if updatedText.isEmpty { parent.value = 0 // 设置空输入时的默认值 return true } if let num = Int(updatedText) { parent.value = num return true } return false } } } // 使用方式 NumberTextField(value: $userViewModel.focusTime, placeholder: "Focus Time") .frame(width: 220) .focused($textIsFocused1) .onTapGesture { textIsFocused1.toggle() }
总结
优先尝试方案1,改动最小且符合SwiftUI原生逻辑;若无法修改ViewModel属性类型,方案2是轻量替代方案;方案3兼容性最强,适合对输入稳定性要求高的场景。
内容的提问来源于stack exchange,提问作者Tracy9988 Xu
相关产品推荐
相关产品推荐

