こちらのアプリを開発しました。
下記のように編集や追加ができるメモ帳を作成する方法について紹介します。
ContentView,AppPeople,DetailViewの3ファイルを用意します。
続いて各ファイルに下記のようなコードを書いていきます。
ContentView
import SwiftUI
// アイテムリストを管理するクラス
class ItemsViewModel: ObservableObject {
@Published var items: [String] {
didSet {
saveItems()
}
}
init() {
// UserDefaultsからアイテムリストを読み込む
self.items = UserDefaults.standard.stringArray(forKey: "SavedItems") ?? ["リンゴ", "バナナ", "オレンジ"]
}
func saveItems() {
// UserDefaultsにアイテムリストを保存する
UserDefaults.standard.set(items, forKey: "SavedItems")
}
}
struct ContentView: View {
@State private var items = ["リンゴ", "バナナ", "オレンジ"]
@State private var showingAddFruit = false // AddFruitView を表示するかどうか
var body: some View {
NavigationStack{
// VStack {
//// Text("ここにリストを表示する")
// // リストの表示
// List(items, id: \.self) { item in
// Text(item)
// }
NavigationView {
List {
ForEach($items.indices, id: \.self) { index in
NavigationLink(destination: DetailView(item: $items[index])) {
Text(items[index])
}
}
.onDelete(perform: deleteItems)
.onMove(perform: moveItems)
}
.navigationBarTitle("フルーツリスト")
.navigationBarItems(leading: EditButton()) // ここで EditButton を追加
.navigationBarItems(trailing: Button(action: {
showingAddFruit = true
}) {
Image(systemName: "plus")
})
.sheet(isPresented: $showingAddFruit) {
AddPeople(items: $items) // バインディングを渡す
}
}//NavigationView
}//NavigationStack
// }
}//body
func deleteItems(at offsets: IndexSet) {
items.remove(atOffsets: offsets)
}
func moveItems(from source: IndexSet, to destination: Int) {
items.move(fromOffsets: source, toOffset: destination)
}
}//ContentView
#Preview {
ContentView()
}
AppPeople
import SwiftUI
struct AddPeople: View {
@Binding var items: [String] // フルーツリストへのバインディング
@State private var newFruitName = "" // 新しいフルーツ名の入力用
@Environment(\.presentationMode) var presentationMode
var body: some View {
NavigationView {
Form {
Section(header: Text("新しいフルーツ")) {
TextField("フルーツ名を入力", text: $newFruitName)
}
Section {
Button("追加") {
addItem()
}
}
}
.navigationBarTitle("フルーツを追加", displayMode: .inline)
.navigationBarItems(trailing: Button("閉じる") {
presentationMode.wrappedValue.dismiss()
})
}
}
func addItem() {
if !newFruitName.isEmpty {
items.append(newFruitName)
newFruitName = "" // テキストフィールドをクリア
presentationMode.wrappedValue.dismiss() // ビューを閉じる
}
}
}
DetailView
import SwiftUI
struct DetailView: View {
@Binding var item: String // 親ビューからのバインディング
@State private var draftItem: String // ローカル状態変数
@Environment(\.presentationMode) var presentationMode
init(item: Binding<String>) {
self._item = item
self._draftItem = State(initialValue: item.wrappedValue) // 初期化時にバインディングの値をコピー
}
var body: some View {
Form {
Section(header: Text("アイテム名")) {
TextField("アイテム名を入力", text: $draftItem) // ローカル状態変数をバインド
}
Section {
Button("保存") {
item = draftItem // 保存ボタンを押したときに変更をコミット
presentationMode.wrappedValue.dismiss()
}
}
}
.navigationTitle("詳細")
.navigationBarTitleDisplayMode(.inline)
}
}
以上、メモ帳アプリでした。
続いてフルーツ名に加えて価格も保存しておけるメモ帳のコードを紹介します。
ContentView
import SwiftUI
// アイテムリストを管理するクラス
class ItemsViewModel: ObservableObject {
@Published var items: [String] {
didSet {
saveItems()
}
}
init() {
// UserDefaultsからアイテムリストを読み込む
self.items = UserDefaults.standard.stringArray(forKey: "SavedItems") ?? ["リンゴ", "バナナ", "オレンジ"]
}
func saveItems() {
// UserDefaultsにアイテムリストを保存する
UserDefaults.standard.set(items, forKey: "SavedItems")
}
}
// Fruit 構造体 (変更なし)
struct Fruit: Identifiable {
let id = UUID() // ForEachで使用するためにIdentifiableプロトコルに準拠
var name: String
var color: String
var price: Double
}
struct ContentView: View {
@State private var fruits = [
Fruit(name: "リンゴ", color: "赤", price: 100),
Fruit(name: "バナナ", color: "黄色", price: 80),
Fruit(name: "オレンジ", color: "オレンジ", price: 120)
]
@State private var showingAddFruit = false // AddFruitView を表示するかどうか
var body: some View {
NavigationStack{
// VStack {
// NavigationView {
List {
ForEach($fruits.indices, id: \.self) { index in
NavigationLink(destination: DetailView(fruit: $fruits[index])) {
VStack {
Text(fruits[index].name)
Spacer()
Text("\(fruits[index].price, specifier: "%.2f")円").foregroundColor(.gray)
}
}
}
.onDelete(perform: deleteItems)
.onMove(perform: moveItems)
}
// }
.navigationBarTitle("フルーツリスト")
.navigationBarItems(leading: EditButton()) // ここで EditButton を追加
.navigationBarItems(trailing: Button(action: {
showingAddFruit = true
}) {
Image(systemName: "plus")
})
.sheet(isPresented: $showingAddFruit) {
// `AddFruitView`に`fruits`配列のバインディングを渡す
AddFruitView(fruits: $fruits)
}//NavigationView
}//NavigationStack
// }
}//body
func deleteItems(at offsets: IndexSet) {
fruits.remove(atOffsets: offsets)
}
func moveItems(from source: IndexSet, to destination: Int) {
fruits.move(fromOffsets: source, toOffset: destination)
}
}//ContentView
#Preview {
ContentView()
}
AppPeople
import SwiftUI
struct AddFruitView: View {
@Binding var fruits: [Fruit]
@Environment(\.dismiss) var dismiss
// 新しいフルーツのための一時的な状態変数
@State private var name: String = ""
@State private var color: String = ""
@State private var price: String = ""
var body: some View {
NavigationView {
Form {
TextField("名前", text: $name)
TextField("色", text: $color)
TextField("価格", text: $price)
Button("追加する") {
if let priceValue = Double(price) {
let newFruit = Fruit(name: name, color: color, price: priceValue)
fruits.append(newFruit)
dismiss()
}
}
}
.navigationTitle("新しいフルーツを追加")
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("キャンセル") {
dismiss()
}
}
}
}
}
}
DetailView
import SwiftUI
struct FruitDetail {
var name: String
var color: String
var price: Double
}
struct DetailView: View {
@Binding var fruit: Fruit // 親ビューからのフルーツのバインディング
@Environment(\.presentationMode) var presentationMode
// フルーツのドラフト状態(編集用)
@State private var draftName: String = ""
@State private var draftColor: String = ""
@State private var draftPrice: Double = 0
init(fruit: Binding<Fruit>) {
self._fruit = fruit
// バインディングから初期値を設定
_draftName = State(initialValue: fruit.wrappedValue.name)
_draftColor = State(initialValue: fruit.wrappedValue.color)
_draftPrice = State(initialValue: fruit.wrappedValue.price)
}
var body: some View {
Form {
Section(header: Text("フルーツ情報")) {
TextField("名前", text: $draftName)
TextField("色", text: $draftColor)
TextField("価格", value: $draftPrice, formatter: NumberFormatter())
}
Section {
Button("保存") {
// ドラフト状態から本番データにコピー
fruit.name = draftName
fruit.color = draftColor
fruit.price = draftPrice
presentationMode.wrappedValue.dismiss()
}
}
}
.navigationTitle("詳細")
.navigationBarTitleDisplayMode(.inline)
}
}
以上、2種類のメモ帳を紹介しました。
コメント