SwiftUI TextField清空后显示残留数字而非0值如何修复
问题描述
在两个使用.percent格式绑定Double类型变量a、b的TextField中分别输入数值(例如依次输入58、78),清空变量a对应的输入框内容后,切换到变量b对应的输入框时,a的输入框不会显示0值,反而残留显示数字5。
复现代码如下:
import SwiftUI struct ContentView: View { @State var a = Double() @State var b = Double() var body: some View { HStack { Text("Number 1") TextField("Enter Number 1", value: $a, format: .percent) } HStack { Text("Number 2") TextField("Enter Number 2", value: $b, format: .percent) } } }
问题原因
系统内置的.percent格式化器接收到空字符串输入时会解析失败,既不会更新绑定的Double值,也不会触发输入框文本重绘,最终导致输入内容、绑定值、UI显示三者不同步,出现字符残留。
修复方案
两种方案都可以实现清空输入、失去焦点后自动显示0值的效果,根据需求选择即可:
- 方案1:最小改动适配,给现有TextField增加编辑状态监听,在编辑结束时通过显式赋值触发UI刷新
import SwiftUI struct ContentView: View { @State var a = Double() @State var b = Double() var body: some View { VStack(spacing: 20) { HStack { Text("Number 1") TextField( "Enter Number 1", value: $a, format: .percent, onEditingChanged: { isEditing in guard !isEditing else { return } // 触发值更新,强制输入框重绘为绑定值对应的格式化文本 let temp = a a = 0 a = temp } ) } HStack { Text("Number 2") TextField( "Enter Number 2", value: $b, format: .percent, onEditingChanged: { isEditing in guard !isEditing else { return } let temp = b b = 0 b = temp } ) } } .padding() } }
- 方案2:自定义格式化器,从解析逻辑层面修复,复用性更高
自定义支持空输入自动转0的百分比格式,空字符串输入时直接解析为0,不需要给每个输入框单独加编辑回调,适合项目中多处使用百分比输入框的场景:
import SwiftUI // 空输入自动返回0的百分比格式化器 struct ZeroDefaultPercentFormat: ParseableFormatStyle { var parseStrategy: Strategy = .init() func format(_ value: Double) -> String { value.formatted(.percent) } struct Strategy: ParseStrategy { func parse(_ value: String) throws -> Double { let content = value.trimmingCharacters(in: .whitespacesAndNewlines) // 空内容、仅输入百分号时都返回0 if content.isEmpty || content == "%" { return 0 } // 正常数值走默认解析逻辑 let numStr = content.replacingOccurrences(of: "%", with: "") guard let num = Double(numStr) else { return 0 } return num / 100 } } } extension ParseableFormatStyle where Self == ZeroDefaultPercentFormat { static var zeroDefaultPercent: ZeroDefaultPercentFormat { .init() } } // 使用方式和系统内置格式完全一致 struct ContentView: View { @State var a = Double() @State var b = Double() var body: some View { VStack(spacing: 20) { HStack { Text("Number 1") TextField("Enter Number 1", value: $a, format: .zeroDefaultPercent) } HStack { Text("Number 2") TextField("Enter Number 2", value: $b, format: .zeroDefaultPercent) } } .padding() } }
内容的提问来源于stack exchange,提问作者Ricky Chhetri
相关产品推荐
相关产品推荐

