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

SwiftUI中TextField绑定值无法随Stepper更新问题求助

问题分析与解决方案

核心问题1:Equatable实现逻辑完全错误

StackOverFlowExampleModel的==方法写反了判断逻辑:

static func == (lhs: StackOverFlowExampleModel, rhs: StackOverFlowExampleModel) -> Bool {
    lhs.id != rhs.id // 此处应为 ==
}

这个错误会导致SwiftUI无法正确识别模型实例的变化——当你修改item.value时,SwiftUI会错误地认为模型没有发生改变,进而不会更新TextField的显示内容。

核心问题2:原始值(ogVal)的记录时机不合理

当前ogVal仅在视图onAppear时赋值,若用户手动修改TextField数值后再使用Stepper,ogVal仍会保留初始的45.0,而非用户更新后的最新值,导致计算逻辑不符合预期。

其他优化点

  • onChange(of: numberOfPeople)无需嵌套在TextField的修饰符中,直接放在视图层级内逻辑更清晰;
  • 未使用的@State var val = Decimal()可删除,减少冗余代码。

修正后的代码

1. 修正Equatable实现的StackOverFlowExampleModel

struct StackOverFlowExampleModel: Identifiable, Equatable {
    static func == (lhs: StackOverFlowExampleModel, rhs: StackOverFlowExampleModel) -> Bool {
        lhs.id == rhs.id // 修正为正确的相等判断
    }

    let id = UUID()
    var name: String
    var value: Decimal?
    var hasFocus: Bool = false
    var selected: (Bool, Color) = (false, .clear)
}

2. 调整逻辑的ExtractedTextField

struct ExtractedTextField: View {
    @Binding var inFocus: Field?
    @State var numberOfPeople = 1
    
    @Binding var item: StackOverFlowExampleModel
    @FocusState private var focus: Bool
    @State var ogVal = Decimal()
    
    var body: some View {
        VStack {
            HStack {
                TextField("Item", text: $item.name, prompt: Text("Item name"))
                    .textFieldStyle(.roundedBorder)
                
                Spacer()
                
                TextField("Value", value: $item.value, format: .currency(code: "USD"))
                    .textFieldStyle(.roundedBorder)
                    .focused($focus)
            }
            
            if focus {
                HStack {
                    Stepper(value: $numberOfPeople) {
                        Text("Split between \(numberOfPeople) people")
                    }
                }
            }
        }
        .onChange(of: focus) { isFocused in
            if isFocused {
                // 获得焦点时记录当前值作为分割计算的原始值
                ogVal = item.value ?? 0.0
                inFocus = .fieldId(item.id)
            }
        }
        .onChange(of: numberOfPeople) { newValue in
            // 根据人数更新分割后的值
            item.value = ogVal / Decimal(newValue)
        }
        .focused($focus)
        .id(item.id)
    }
}

修正后效果说明

  1. 修正Equatable逻辑后,SwiftUI能正确检测item.value的变化,TextField会实时显示计算后的数值;
  2. 仅在TextField获得焦点时记录原始值,确保分割计算使用的是当前最新的输入值;
  3. 调整onChange的位置,让代码逻辑更直观易读。

内容的提问来源于stack exchange,提问作者Eric Agredo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 08:02:59