Swiftでメモ帳アプリを作成する方法

こちらのアプリを開発しました。

シンプル婚活記録
シンプル婚活記録
無料
posted withアプリーチ

下記のように編集や追加ができるメモ帳を作成する方法について紹介します。

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種類のメモ帳を紹介しました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次