自定义SwiftUI Binding值转换后如何正确实现Setter获取最新输入值
问题根源
你当前的Binding setter没有任何存储逻辑,仅返回输入的新值,没有同步到任何存储载体。而Binding的getter每次取值都会从app.flight.duration读取原始Int值再格式化,自然永远只能拿到初始转换后的结果。
方案1:反向解析输入内容同步回数据源(推荐)
这是最符合业务设计的用法,输入内容最终要更新到数据库对应的duration字段,只需要补全字符串转Int分钟数的反向逻辑即可。
首先给String添加反向转换扩展,根据当前选中的格式(HHMM/小数小时)把输入内容解析为分钟数:
extension String { /// 根据格式将输入字符串转换为分钟数,返回nil代表输入非法 func toMinutes(isHHMMFormat: Bool) -> Int? { if isHHMMFormat { // HHMM格式解析逻辑,例如输入130返回1小时30分=90分钟 guard let num = Int(self), num >= 0 else { return nil } let hours = num / 100 let minutes = num % 100 guard minutes < 60 else { return nil } return hours * 60 + minutes } else { // 小数小时格式解析逻辑,例如输入1.5返回90分钟 guard let hourValue = Double(self) else { return nil } return Int(hourValue * 60) } } }
修改你的Binding实现:
let time = Binding( get: { app.flight.duration.timeForm }, set: { newValue in guard let validMinutes = newValue.toMinutes(isHHMMFormat: timeDisplayHHMM) else { // 可在这里添加非法输入的容错处理,比如弹窗提示、重置输入等 return } app.flight.duration = validMinutes } )
此时onCommit中读取time.wrappedValue会自动从更新后的app.flight.duration重新格式化返回,和用户输入的有效内容完全一致。
方案2:临时存储输入内容(无需反向解析)
如果你暂时不需要同步回数据源,仅需要拿到用户输入的原始字符串,可以在视图中新增@State作为临时存储载体:
// 在视图结构体中添加临时存储变量 @State private var tempInput: String = "" let time = Binding( get: { // 初始无输入时返回格式化的原始值,有输入时返回用户输入内容 tempInput.isEmpty ? app.flight.duration.timeForm : tempInput }, set: { newValue in tempInput = newValue } )
这种方案可以直接拿到用户输入的原始字符串,不需要做格式校验,适合需要额外校验后再提交的场景。
内容的提问来源于stack exchange,提问作者Clifton Labrum
相关产品推荐
相关产品推荐

