【问题标题】:SwiftUI. How do I access/manipulate data between views斯威夫特用户界面。如何访问/操作视图之间的数据
【发布时间】:2020-10-02 21:27:51
【问题描述】:

这段代码不是我的专用代码,但它会更清楚地显示我遇到的问题。它是费用计算应用程序的一部分。在视图之间传输数据后,我很难处理数据。我有 2 个视图,我想把所有的费用加起来。部分问题是我每次添加新的“费用”时都会创建一个类的新实例。

import SwiftUI

struct AddView: View {
    @Environment(\.presentationMode) var presentationMode
    @ObservedObject var expenses: Expenses

    @State private var name = ""
    @State private var type = "Personal"
    @State private var amount = ""
    static let types = ["Business", "Personal"]

    var body: some View {
        NavigationView {
            Form {
                TextField("Name", text: $name)

                Picker("Type", selection: $type) {
                    ForEach(Self.types, id: \.self) {
                        Text($0)
                    }
                }

                TextField("Amount", text: $amount)
                    .keyboardType(.numberPad)
            }
            .navigationBarTitle("Add new expense")
            .navigationBarItems(trailing: Button("Save") {
                if let actualAmount = Int(self.amount) {
                    let item = ExpenseItem(name: self.name, type: self.type, amount: actualAmount)
                    self.expenses.items.append(item)
                    self.presentationMode
                        .wrappedValue.dismiss()
                }
            })
        }
    }
}

//第二视图

import SwiftUI

struct ExpenseItem: Identifiable, Codable {

let id = UUID()
let name: String
let type: String
let amount: Int
}

class Expenses: ObservableObject {
    @Published var items = [ExpenseItem]() {
        didSet {
            let encoder = JSONEncoder()

            if let encoded = try?
                encoder.encode(items) {
                UserDefaults.standard.set(encoded, forKey: "Items")
            }
        }
    }

    init() {
        if let items = UserDefaults.standard.data(forKey: "Items") {
            let decoder = JSONDecoder()

            if let decoded = try?
                decoder.decode([ExpenseItem].self, from: items) {
                self.items = decoded
                return
            }
        }
    }
}

struct ContentView: View {
    @ObservedObject var expenses = Expenses()
    @State private var showingAddExpense = false

    var body: some View {
        NavigationView {
            List {
                ForEach(expenses.items) { item in
                    HStack {
                        VStack {
                            Text(item.name)
                                .font(.headline)
                            Text(item.type)
                        }

                        Spacer()
                        Text("$\(item.amount)")
                    }
                }
                .onDelete(perform: removeItems)
            }
            .navigationBarTitle("iExpense")
            .navigationBarItems(trailing: Button(action: {
                self.showingAddExpense = true
            }) {
                Image(systemName: "plus")
                }
            )
            .sheet(isPresented: $showingAddExpense) {
                AddView(expenses: self.expenses)
            }
        }
    }

    func removeItems(at offsets: IndexSet) {
        expenses.items.remove(atOffsets: offsets)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

【问题讨论】:

  • 听起来代码是别人写的,但是你能分享你自己定制的部分吗?不幸的是,如果没有一些代码示例,将很难确定问题所在。
  • 我很抱歉。我不小心提交了帖子而没有附加我的代码!这段代码来自“HackingWithSwift”,是他的“iExpenses”SwiftUI 教程。我的应用程序基于它。重申一下,我正在尝试计算费用金额并将所有条目加在一起。希望这可以帮助。谢谢!

标签: json swift swift3 swift2 swiftui


【解决方案1】:

这真的取决于你想在哪里显示总数。最简单的解决方案是在ContentView 的所有费用列表之后显示总计。

但首先我们需要计算总数。由于总数与我们的Expenses ObservableObject 相关,因此它计算它是自己的总数是有道理的。

Expenses 类只有一个实例,它包含ExpenseItem 结构的多个实例。我们将通过向Expenses 类添加一个计算属性来解决这个问题。我已从您的示例中删除了一些代码,以突出显示我所做的更改。

class Expenses: ObservableObject {
    @Published var items: [ExpenseItem]

    // ...

    // Computed property that calculates the total amount
    var total: Int {
        self.items.reduce(0) { result, item -> Int in
            result + item.amount
        }
    }
}

计算的属性总计将所有ExpenseItem 数量减少为一个值。您可以阅读有关 reduce here 的更多信息,也可以阅读有关计算属性 here 的信息。我们不必使用reduce,我们可以使用for循环并对值求和。我们也不必使用计算属性,我们可以使用函数。这真的取决于你想要什么。

接下来在ContentView 中,我们可以向List 添加一个显示总数的视图。

struct ContentView: View {
    @ObservedObject var expenses = Expenses()
    @State private var showingAddExpense = false

    var body: some View {
        NavigationView {
            List {
                ForEach(expenses.items) { item in
                   // ...
                }
                .onDelete(perform: removeItems)

                // View that shows the total amount of the expenses
                HStack {
                    Text("Total")
                    Spacer()
                    Text("\(expenses.total)")
                }
            }
            // ...
    }
     // ...
}

这将为您提供如下所示的结果。

【讨论】:

  • 就是这样!感谢您的回答,您的解释非常好!
猜你喜欢
  • 2023-03-14
  • 2018-02-10
  • 1970-01-01
  • 2020-03-26
  • 1970-01-01
  • 2020-01-01
  • 1970-01-01
  • 2023-02-23
  • 2017-07-22
相关资源
最近更新 更多