SwiftUI - передавать данные в разные представления - PullRequest
1 голос
/ 16 января 2020

Я работаю над приложением, которое имеет 4 разных вида. Основное представление ( ContentView ), AddView , EditView и отдельный DataView с классом, в который передаются все данные ObservableObject для других представлений.

В главном представлении у меня есть список элементов. В AddView я добавляю элементы в этот список и из ContentView . Я хотел бы иметь возможность редактировать добавленные элементы с помощью навигационной ссылки. Поэтому на главном экране я бы хотел go на EditView , изменить значения и go снова на ContentView снова, где я вижу измененные значения.

Вы бы использовали ObservableObject для этого или мне нужен EnvironmentObject? Поскольку в настоящее время EditView не работает, я не могу передать данные из ContentView в EditView , все текстовые поля в EditView пусты, значения не передаются. Он работает для передачи данных из AddView в ContentView , но не из ContentView в EditView .

Может кто-то скажите, как данные должны быть связаны со всеми представлениями?

1 Ответ

3 голосов
/ 16 января 2020

Вы должны использовать @EnvironmentObject. Это позволяет совместно использовать объект, что очень важно для обмена данными с другими представлениями.

В этом примере я использую объект Shopping. Это приложение будет действовать как список покупок. Весь этот проект доступен на GitHub здесь .

Я действительно надеюсь, что это полезно, так как это заняло довольно много времени. Это всего лишь общий пример того, как эффективно использовать @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 s работать (кредит здесь , хотя это было упрощено):

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
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...