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

Posted

技术标签:

【中文标题】Swift UI 如何从子视图中检索状态【英文标题】:Swift UI how to retrieve state from child view 【发布时间】:2020-07-04 13:01:18 【问题描述】:

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

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

我是 SwiftUI 的新手,所以可能会遗漏一些明显的东西,但这是我的代码。我在 ContentView 中尝试了 @State 对象,在 ChildPickerView 中尝试了 @Binding,但我的问题是构建复合文本视图,以跟踪我最终要保存并显示在 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)
                
            
        
    

【问题讨论】:

您需要更改应用的架构。 States 应该始终是每个 view 私有的。 【参考方案1】:

在 SwiftUI 中,您需要数据的单一真实来源,然后所有视图都读取和写入该数据。

@State 有点像 private,因为它创建了一个新的事实来源,只能由该视图(及其子视图)使用。

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

您可以使用@Binding

public struct ChildPickerView : View 

    var selectedText: Binding<String>

    var body: some View  

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

public struct ContentView : View 
    @State var selectedText = ""

    var body: some View 
      ChildViewItem($selectedText) 
    

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

【讨论】:

我编辑了我的代码以显示父级中的 '@State' var 和子级中的 '@Binding' var,但仍然不知道如何将子级中的 var 正确设置为退货 List 之前声明您的变量,然后添加return List 。 SwiftUI 视图中的代码有一个隐含的return。如果你想在那里运行其他代码,你必须显式地return一个视图。

以上是关于Swift UI 如何从子视图中检索状态的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:从子级检索***状态返回null

如何使用 JCR 中的 SQL 从子名称中检索父名称

如何从子文件夹中检索文件名

如何从 Swift 中嵌入 UITableView 的文本字段中检索数据?

在 SQL Server 中,如何从子查询中标识的表列名称中检索数据值?

使用 swift 将数组保存和检索到用户默认值