繁体   English   中英

动态访问SwiftUI中的TextField

[英]Dynamically access TextField in SwiftUI

我正在 VStack 中动态创建一个 TextField。 这里 TextFields 的创建如下:

struct Input: View {
    
    var title: String
    @State var value:String
    var disableInputMode:Bool = true

    var body: some View {                
        VStack {
            Text(title)
                .frame(maxWidth: .infinity, alignment: .leading)
                .foregroundColor(Color("SecondaryTextColor"))
            TextField("", text: $value)
                .disabled(disableInputMode)
                .frame(maxWidth: .infinity, alignment: .leading)
            Divider()
        }
        .padding()        
    }
}

这些 TextFields 依赖于其他一些数据字段(在运行时决定):

ScrollView {
    VStack {
        ForEach(detailsViewModel.details) { datum in
            Input(title: datum.title, value: datum.detail!)
        }
    }.frame(maxWidth: .infinity)
    .padding()
}.background(Color("Light"))
.cornerRadius(25)
.padding()

现在,当用户输入数据并尝试应用时,我找不到如何从其他视图获取这些输入。 从本例中的示例 - 从上面的视图。

解决方案 1 (iOS 14 *)

使用onChange修饰符检测 TextField 值更改并将其更新为您的 model。

struct Input: View {
    
    var title: String
    @State var value:String
    var disableInputMode:Bool = false
    
    var onTextChange: ((String) -> Void)?

    var body: some View {
        VStack {
            Text(title)
                .frame(maxWidth: .infinity, alignment: .leading)
                .foregroundColor(Color("SecondaryTextColor"))
            TextField("", text: $value)
                .onChange(of: value) {
                    // Called each time value changes.
                    if onTextChange != nil {
                        onTextChange!($0)
                    }
                }
                .disabled(disableInputMode)
                .frame(maxWidth: .infinity, alignment: .leading)
            Divider()
        }
        .padding()
    }
}

解决方案 2 (iOS 13 *)

扩展绑定以处理自定义 onChange

extension Binding {
    func onChange(_ handler: @escaping (Value) -> Void) -> Binding<Value> {
        Binding(
            get: { self.wrappedValue },
            set: { newValue in
                self.wrappedValue = newValue
                handler(newValue)
            }
        )
    }
}

然后你的输入视图变成

struct Input: View {
    
    var title: String
    @State var value:String
    var disableInputMode:Bool = false
    
    var onTextChange: ((String) -> Void)?

    var body: some View {
        VStack {
            Text(title)
                .frame(maxWidth: .infinity, alignment: .leading)
                .foregroundColor(Color("SecondaryTextColor"))
            TextField("", text: $value.onChange(textChanged))
                .disabled(disableInputMode)
                .frame(maxWidth: .infinity, alignment: .leading)
            Divider()
        }
        .padding()
    }
    
    func textChanged(to value: String) {
        // Called each time value changes.
        if onTextChange != nil {
            onTextChange!(value)
        }
    }
}

如何使用:

这两种解决方案都可以使用您的输入视图,如下所示。

ScrollView {
    VStack {
        ForEach(detailsViewModel.details) { datum in
            Input(title: datum.title, value: datum.detail) { newValue in
                // Each time you will get the update
                // Do what ever you want to do with the new value
                // something like
                // detailsViewModel.update(value: newValue, forItem: datum.id)
                print("Text value for \(datum.id) :", newValue)
            }
        }
    }.frame(maxWidth: .infinity)
    .padding()
}.background(Color("Light"))
.cornerRadius(25)
.padding()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM