削除できるリストを作成する
Building a list we can delete from
import SwiftUI ファイル名;iExpense struct ContentView: View { struct ExpenseItem { let name: String let type: String let amount: Int } class Expenses: ObservableObject { @Published var items = [ExpenseItem]() } @ObservedObject var expenses = Expenses() func removeItems(at offsets: IndexSet) { expenses.items.remove(atOffsets: offsets) } var body: some View { NavigationView { List { ForEach(expenses.items, id: \.name) { item in Text(item.name) } .onDelete(perform: removeItems) } .navigationBarTitle("iExpense") .navigationBarItems(trailing: Button(action: { let expense = ExpenseItem(name: "Test", type: "Personal", amount: 5) self.expenses.items.append(expense) }) { Image(systemName: "plus") } ) } } }
SwiftUIWorking with Identifiable items in SwiftUI
識別可能なアイテムを操作する
UUIDは「普遍的に一意の識別子
UUIDは、08B15DB4-2F02-4AB8-A965-67A9C90D8A44のような長い16進文字列です。したがって、これは8桁、4桁、4桁、4桁、12桁の数字であり、3番目のブロックの最初の数字に4があることが唯一の要件です。固定の4を減算すると、31桁になり、それぞれが16の値のいずれかになります。
Identifiable これはSwiftに組み込まれているプロトコルの1つであり、「このタイプは一意に識別できる」ことを意味します。
import SwiftUI //------------------------------ struct ExpenseItem: Identifiable { let id = UUID() let name: String let type: String let amount: Int } //------------------------------ class Expenses: ObservableObject { @Published var items = [ExpenseItem]() } //------------------------------ struct ContentView: View { @State private var showingAddExpense = false @ObservedObject var expenses = Expenses() func removeItems(at offsets: IndexSet) { expenses.items.remove(atOffsets: offsets) } var body: some View { NavigationView { List { ForEach(expenses.items) { item in Text(item.name) } .onDelete(perform: removeItems) } .navigationBarTitle("iExpense") .navigationBarItems(trailing: Button(action: { let expense = ExpenseItem(name: "Test", type: "Personal", amount: 5) self.expenses.items.append(expense) }) { Image(systemName: "plus") } ) // .sheet(isPresented: $showingAddExpense) { // // show an AddView here // AddView(expenses: self.expenses) // } } } } //------------------------------
監視対象オブジェクトを新しいビューと共有する
Sharing an observed object with a new view
準拠するクラスはObservableObject、複数のSwiftUIビューで使用できます。これらのビューはすべて、クラスの公開されたプロパティが変更されると更新されます。
ファイル名;AddView.swift
struct AddView: View { @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") } } } struct AddView_Previews: PreviewProvider { static var previews: some View { AddView(expenses: Expenses()) } } //-------------------------------------------------- struct ExpenseItem: Identifiable { let id = UUID() let name: String let type: String let amount: Int } class Expenses: ObservableObject { @Published var items = [ExpenseItem]() } struct ContentView: View { @State private var showingAddExpense = false @ObservedObject var expenses = Expenses() func removeItems(at offsets: IndexSet) { expenses.items.remove(atOffsets: offsets) } var body: some View { NavigationView { List { ForEach(expenses.items) { item in Text(item.name) } .onDelete(perform: removeItems) } .navigationBarTitle("iExpense") .navigationBarItems(trailing: Button(action: { self.showingAddExpense = true }) { Image(systemName: "plus") } ) .sheet(isPresented: $showingAddExpense) { AddView(expenses: self.expenses) } } } }
+ボタンをタップAddViewして、さまざまなフィールドに入力できる場所を表示し、スワイプして閉じることができます。
UserDefaultsで変更を永続的にする
Making changes permanent with UserDefaults
次に、presentationMode.wrappedValue.dismiss()ビューにそれ自体を閉じさせたいときに呼び出す必要があります。これにより、showingAddExpensein のブール値がContentViewfalseに戻り、が非表示になりAddViewます。AddView新しい経費項目を作成して既存の経費に追加する[保存]ボタンが既にあるので、次の直後の行にこれを追加します。
isPresentedシートのパラメーターにリンク
self.presentationMode.wrappedValue.dismiss()
struct AddView: View { @ObservedObject var expenses: Expenses //追加 @Environment(\.presentationMode) var presentationMode @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) } //追加 isPresentedシートのパラメーターにリンク self.presentationMode.wrappedValue.dismiss() }) } } } struct AddView_Previews: PreviewProvider { static var previews: some View { AddView(expenses: Expenses()) } } //-------------------------------------------------- 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]() @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 } } self.items = [] } } //--------------------------------------- struct ContentView: View { @State private var showingAddExpense = false @ObservedObject var expenses = Expenses() func removeItems(at offsets: IndexSet) { expenses.items.remove(atOffsets: offsets) } var body: some View { NavigationView { List { ForEach(expenses.items) { item in HStack { VStack(alignment: .leading) { 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) } } } }