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

Dis*_*ace 4 xcode swift swiftui

我正在开发一个有 4 个不同视图的应用程序。主视图(ContentView)、一个AddView、一个EditView和一个分离的DataView,其中包含一个类,我通过ObservableObject将所有数据传递给其他视图。

在主视图中,我有一个项目列表。在AddView 中,我将项目添加到该列表和ContentView。我希望能够使用导航链接编辑添加的项目。所以从主视图我想转到EditView,更改值并再次返回ContentView,在那里我看到更改的值。

你会使用ObservableObject来做这件事还是我需要 EnvironmentObject?因为此刻EditView不工作,我无法将数据从ContentView传递到EditViewEditView 上的所有文本字段都是空的,值不会被传递。它可以将数据从AddView 传递ContentView而不是从ContentView传递到EditView

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

Geo*_*e_E 12

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

Shopping在这个例子中使用了一个对象。这个应用程序就像一个购物清单。这整个项目可GitHub上的位置

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

该应用程序如下所示:

应用程序的外观


创建项目

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

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

let contentView = ContentView()
Run Code Online (Sandbox Code Playgroud)

和:

let contentView = ContentView().environmentObject(Shopping())
Run Code Online (Sandbox Code Playgroud)

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
    }
}
Run Code Online (Sandbox Code Playgroud)

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)
            }))
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

4:随着这个extension让 optional @States 工作(信用在这里,虽然这已经简化了):

extension Optional where Wrapped == String {

    var bound: String {
        get {
            return self ?? ""
        }
        set {
            self = newValue
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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
    }
}
Run Code Online (Sandbox Code Playgroud)