SwiftUI-将数据传递到不同的视图

时间:2020-01-16 13:05:16

标签: swift xcode swiftui

我正在开发一个具有4种不同视图的应用程序。主视图( ContentView ), AddView EditView 和带有类的单独的 DataView ObservableObject 将所有数据传递到其他视图。

在主视图中,我有一个项目列表。在 AddView 中,我从 ContentView 向该列表添加项目。我希望能够通过使用导航链接来编辑添加的项目。因此,从主视图中,我想转到 EditView ,更改值,然后再次回到 ContentView ,在此我看到更改的值。

您将使用 ObservableObject 还是我需要EnvironmentObject?由于目前 EditView 无法正常工作,因此我无法将数据从 ContentView 传递给 EditView EditView 为空,不会传递值。它可以将数据从 AddView 传递到 ContentView ,而不是从 ContentView 传递到 EditView

有人可以告诉我如何将数据链接到所有视图吗?

1 个答案:

答案 0 :(得分:6)

您应该使用@EnvironmentObject。它允许共享对象,这对于将数据共享给其他视图非常重要。

在此示例中,我正在使用Shopping对象。该应用程序将像购物清单一样。整个项目可从GitHub here获得。

我真的希望这很有用,因为它花了很长时间。这只是在@EnvironmentObject之间有效使用View一般示例。

该应用程序如下所示:

How the app looks


创建项目

(可以通过GitHub下载,请参见上面的链接)

1::首先,在您的SceneDelegate.swift中,替换:

let contentView = ContentView()

具有:

let contentView = ContentView().environmentObject(Shopping())

2 :Xcode现在会抱怨尚未制作Shopping,因此我们将在下一个解决此问题:

class Shopping: ObservableObject {
    
    @Published var list = [
        ShoppingItem("Bread", quantity: 1),
        ShoppingItem("Milk", quantity: 2),
        ShoppingItem("Eggs", quantity: 12)
    ]
    
    func addItem(_ item: ShoppingItem) {
        list.append(item)
    }
}


class ShoppingItem: Identifiable {
    
    var name: String
    var quantity: Int
    
    init(_ name: String, quantity: Int) {
        self.name = name
        self.quantity = quantity
    }
}

3:接下来,我们需要主要内容ContentView

struct ContentView: View {

    @EnvironmentObject private var shopping: Shopping
    @State private var newItem: String?
    
    var body: some View {
        NavigationView {
            List {
                ForEach(shopping.list) { item in
                    NavigationLink.init(destination: EditView(currentItem: item)) {
                        HStack {
                            Text(item.name)
                            Spacer()
                            Text(String(item.quantity))
                            Spacer().frame(width: 10)
                        }
                    }
                }
                
                if newItem != nil {
                    TextField("New Item", text: $newItem.bound, onCommit: {
                        if !self.newItem!.isEmpty {
                            self.shopping.addItem(ShoppingItem(self.newItem!, quantity: 1))
                        }
                        self.newItem = nil
                    })
                }
            }
            .navigationBarTitle("Shopping List")
            .navigationBarItems(trailing: Button(action: {
                self.newItem = ""
            }, label: {
                Image(systemName: "plus.circle.fill")
                    .resizable()
                    .frame(width: 25, height: 25)
            }))
        }
    }
}

4::与此extension一起使用,以使可选@State起作用(信用here,尽管已简化):

extension Optional where Wrapped == String {

    var bound: String {
        get {
            return self ?? ""
        }
        set {
            self = newValue
        }
    }
}

5:然后最后是EditView,可让您编辑购物清单中商品的名称:

struct EditView: View {

    let currentItem: ShoppingItem
    @EnvironmentObject private var shopping: Shopping
    @State private var name = ""
    
    var body: some View {
        TextField("Item", text: $name, onCommit: saveName)
            .padding()
            .background(Color.gray)
            .onAppear(perform: setName)
    }
    
    private func saveName() {
        shopping.objectWillChange.send()
        currentItem.name = name
    }
    private func setName() {
        name = currentItem.name
    }
}