微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

SwiftUI 模型绑定仅在第一次通过时更新值

如何解决SwiftUI 模型绑定仅在第一次通过时更新值

我正在尝试使用 SwiftUI 创建表单框架。现在,我正在保存我的 FormFieldModels 字典,以保存有关该字段是否为必填字段、它是什么类型的字段(文本、复选框、电话等)及其值的信息。我对 SwiftUI 的经验并不丰富,但我正在尝试将字段绑定到自定义文本字段视图/复选框(最终将是更多字段选项),然后使用字段中包装的值来确定状态。>

出于我不完全理解的原因,只有来自任何字段(无论是文本字段还是切换按钮)的第一次更新有效,然后其余字段不更新主字段的状态ContentView(虽然它们的新值被正确传递,但它只是不粘连)。

代码

import SwiftUI

enum FormFieldType: Hashable,Equatable {
    
    case plainText
    case checkBox
    case ageGate
    case phone
    case picker([String])
        
}

struct FormFieldModel: Hashable {
    
    //Constants
    let title: String
    let type: FormFieldType
    let required: Bool
    var value: Any?
    
    func validate() -> Bool {
        switch type {
        case .phone:
            return false
        default:
            return true
        }
    }
    
    //MARK: Equatable Conformance
    static func == (lhs: FormFieldModel,rhs: FormFieldModel) -> Bool {
        return lhs.title == rhs.title
            && lhs.type == rhs.type
            && lhs.required == rhs.required
    }
    
    func hash(into hasher: inout Hasher) {
        hasher.combine(title)
        hasher.combine(type)
        hasher.combine(required)
    }
    
}

struct Addressviewmodel {
    let first:String
    let last:String
}

struct ContentView: View {
    
    enum FieldKey: String {
        case first,last,enroll
    }
    
    var existingAddress: Addressviewmodel?
    @State var fields:[FieldKey:FormFieldModel] = [.first : .init(title: "First Name",type: .plainText,required: true,value: nil),.last  : .init(title: "Last Name",.enroll : .init(title: "Enroll",type: .checkBox,value: nil)]
    {
        didSet {
            print("fields has been modified")
            let v = fields[.first]?.value as? String ?? "none"
            print("new value of first is \(v)")
        }
    }
    
    var body: some View {
        vstack {
            FloatingTextField(model: binding(for: .first))
            FloatingTextField(model: binding(for: .last))
            CheckBoxView(model: binding(for: .enroll))
            Button("Print Values") {
                printValues()
            }
            Spacer()
        }
        .padding()
    }
    
    func printValues() {
        print("\(FieldKey.first.rawValue): \(fields[.first]?.value ?? "none")")
        print("\(FieldKey.last.rawValue): \(fields[.last]?.value ?? "none")")
        print("\(FieldKey.enroll.rawValue): \(fields[.enroll]?.value ?? "none")")
    }
    
    func binding(for key: FieldKey) -> Binding<FormFieldModel> {
        return Binding(get: {
            return self.fields[key]!
        },set: {
            print("Model is being set with value \($0)")
            self.fields[key] = $0
            print("Fields is \(self.fields)")
            print("-------------------------------------------------------")
        })
    }
    
}

struct FloatingTextField: View {
    
    let model: Binding<FormFieldModel>
    var text: Binding<String> {
        Binding {
            return self.model.wrappedValue.value as? String ?? ""
        } set: {
            print("Setting value to \($0)")
            self.model.wrappedValue.value = $0
        }
    }
    
    var body: some View {
        ZStack(alignment: .leading) {
            Text(model.wrappedValue.title)
                .foregroundColor(Color(.placeholderText))
                .offset(y: text.wrappedValue.isEmpty ? 0 : -25)
                .scaleEffect(text.wrappedValue.isEmpty ? 1 : 0.8,anchor: .leading)
            TextField("",text: text) // give TextField an empty placeholder
        }
        .padding(.top,15)
        .animation(.spring(response: 0.2,dampingFraction: 0.5))
        .overlay(
            RoundedRectangle(cornerRadius: 8)
                .stroke(Color.blue,linewidth: 1.5)
        )
    }
    
}

struct CheckBoxView: View {
    
    let model: Binding<FormFieldModel>
    var selected: Binding<Bool> {
        Binding {
            return self.model.wrappedValue.value as? Bool ?? false
        } set: {
            self.model.wrappedValue.value = $0
        }
    }
    
    var body: some View {
        HStack {
            Button(selected.wrappedValue ? "selected" : "deselected") {
                selected.wrappedValue.toggle()
            }
            Text("Enroll?")
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        let address:Addressviewmodel = .init(first: "Matt",last: "Gannon")
        ContentView(existingAddress: address)
    }
}

在文本字段之一中键入时,程序会打印以下内容。如您所见,仅保留输入的第一个字母:

Setting value to B
Model is being set with value FormFieldModel(title: "First Name",type: FormUI.FormFieldType.plainText,value: Optional("B"))
fields has been modified
new value of first is B
Fields is [FormUI.ContentView.FieldKey.first: FormUI.FormFieldModel(title: "First Name",value: Optional("B")),FormUI.ContentView.FieldKey.enroll: FormUI.FormFieldModel(title: "Enroll",type: FormUI.FormFieldType.checkBox,FormUI.ContentView.FieldKey.last: FormUI.FormFieldModel(title: "Last Name",value: nil)]
-------------------------------------------------------
Setting value to Bo
Model is being set with value FormFieldModel(title: "First Name",value: Optional("Bo"))
fields has been modified
new value of first is B
Fields is [FormUI.ContentView.FieldKey.first: FormUI.FormFieldModel(title: "First Name",value: nil)]
-------------------------------------------------------
Setting value to Bob
Model is being set with value FormFieldModel(title: "First Name",value: Optional("Bob"))
fields has been modified
new value of first is B
Fields is [FormUI.ContentView.FieldKey.first: FormUI.FormFieldModel(title: "First Name",value: nil)]
-------------------------------------------------------

感谢任何提示。我确定我在这里误解了有关 @State 或 Binding 的内容,这导致了混乱。谢谢

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?