You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级至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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 14:35:31