Swift UI如何从子视图中检索状态

时间:2020-07-04 13:01:18

标签: swiftui parent-child picker swiftui-form

我有一个当前具有三个视图的应用程序,一个ParentView是一个简单的列表,用户可以向其中添加条目,一个ContentView是一个模态形式,用于收集信息以将列表添加到ParentView中,以及一个ChildPickerView重构了ContentView中的一些代码,这些代码得到了可怕的“编译器无法在合理的时间内对这种表达式进行类型检查”消息。

我的问题是ChildPickerView包含需要保存的文本。它随着3个选择器的更改而更新。在ContentView中点击“保存”时,我试图将选择器返回的复合文本保存在ChildPickerView中。

我是SwiftUI的新手,因此可能缺少明显的内容,但这是我的代码。我在ContentView中尝试了@State对象,在ChildPickerView中尝试了@Binding,但是我的问题是构建复合Text视图,该视图跟踪最终要保存并显示在ParentView列表中的选择器的状态。 >

这是我的代码(为简单起见,我仅包括ContentView和ChildPickerView的代码:

struct ContentView: View {
    @State private var isCustomWidget: Bool = false
    @State private var customWidgetName: String = ""
    @State private var standardWidgetName: String = ""
    var body: some View {
        NavigationView {
            Form {
                Section(header: Text("WIDGET DETAILS")) {
                    Toggle(isOn: self.$isCustomWidget) {
                        Text("Custom")
                    }
                    if !self.isCustomWidget {
                        ChildPickerView(standardWidgetName: $standardWidgetName)
                    }
                    else
                    {
                        TextField("enter custom widget name", text: $customWidgetName)
                    }
                }
                
                Button(action: {
                    // we want to save either the standard widget name or custom widget name to our store
                    let str = self.isCustomWidget ? customWidgetName : standardWidgetName
                     print("saving \(str)")
                    
                })
                {
                    Text("Save")
                }
                .navigationBarTitle("Add Widget")
            }
        }
    }
    
}

struct ChildPickerView: View {
    @State var selectedLengthIndex = 0
    @State var selectedUnitsIndex = 0
    @State var selectedItemIndex = 0
    @Binding var standardWidgetName: String

    var length: [String] =  ["1","5","10","20","40","50","100","200"]
    var units: [String] =  ["Inches", "Centimeters"]
    var items: [String] = ["Ribbon","Cord","Twine", "Rope"]
        
    var body: some View {
        List {
            HStack {
                Text("Widget Name")
                Spacer()
                let name =
                    "\(length[selectedLengthIndex])" + " " + " \(units[selectedUnitsIndex])" + " " + " \(items[selectedItemIndex])"
                standardWidgetName = name  //generates error on HStack -> Type '()' cannot conform to 'View'; only struct/enum/class types can conform to protocols
                Text(name)
            }
            
            Picker(selection: $selectedLengthIndex, label: Text("Length")) {
                ForEach(0 ..< length.count) {
                    Text(self.length[$0]).tag($0)
                }
            }
            
            Picker(selection: $selectedUnitsIndex, label: Text("Unit of Measure")) {
                ForEach(0 ..< units.count) {
                    Text(self.units[$0]).tag($0)
                }
            }
            
            Picker(selection: $selectedItemIndex, label: Text("Item Type")) {
                ForEach(0 ..< items.count) {
                    Text(self.items[$0]).tag($0)
                }
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

在SwiftUI中,您想要数据的单一真实来源,然后所有视图都对该数据进行读写。

@State有点像私有,因为它创建了只能由该视图(及其子视图)使用的新真理源。

您想要的是将数据保存在Parent(在本例中为ContentView)中,然后将您希望孩子更新的数据传递给他们。

您可以使用@Binding进行此操作:

公共结构ChildPickerView:查看{

var selectedText: Binding<String>

var body: some View { }

}

然后使用$从父级传递该绑定:

公共结构ContentView:查看{ @State var selectedText =“”

var body: some View {
  ChildViewItem($selectedText) 
}

}

您还可以使用EnvironmentObject来避免在视图之间传递数据。