[SwiftUI] リストの編集と更新

投稿日:

更新日:

カテゴリ:

モバイルアプリには、リストはよくある画面構成だと思います。

表示するだけならさほど難しくないのかなと思いますが、表示されている内容を編集し、さらに編集後のデータをリストに反映されるには少しハードルが上がります。

実際リストを使う時は、内容の更新も普通にあると思いますので、例としてここに書き残します。

Table of Contents

ソース

全体のソースは以下です。

//
//  TestListView.swift
//  UkiCalendar
//
//  Created by ukiLab on 2024/05/02.
//

import SwiftUI

// 行のレイアウト
struct RowView: View {
  let row: Row

  var body: some View {
    HStack {
      Text(row.name)
      Text(row.description)
    }
  }
}

// 行ごとのデータ構造
struct Row: Identifiable {
  let id = UUID()
  var name: String
  var description: String
}

// 編集画面
struct EditSheet: View {
  @Binding var rowBeingEdited: Row

  var body: some View {
    VStack {
      TextField("Name", text: $rowBeingEdited.name) // ③
      TextField("Description", text: $rowBeingEdited.description) // ③
    }
  }
}

// リスト画面
struct TestListView: View {
  @State var rows: [Row] = [Row(name: "Name1", description: "Description1"),
                            Row(name: "Name2", description: "Description2"),
                            Row(name: "Name3", description: "Description3"),
                            Row(name: "Name4", description: "Description4"),
                            Row(name: "Name5", description: "Description5"),
                            Row(name: "Name6", description: "Description6")]
  @State var rowID: UUID?

  var body: some View {
    NavigationView {
      List {
        ForEach($rows) { $row in
          RowView(row: row)
            // セルにスワイプすると編集ボタンが表示されます
            .swipeActions(edge: .trailing, allowsFullSwipe: false) {
              Button(action: {
                rowID = row.id
              }) {
                Label("Edit", systemImage: "rectangle.and.pencil.and.ellipsis")
              }
            }
            .sheet(isPresented: Binding<bool>( // ①
              get: { row.id == rowID },
              set: { _ in
                rowID = nil
              })
            ) {
              EditSheet(rowBeingEdited: $row) // ②
            }
        }
      }
      .navigationBarTitle("サンプルリスト", displayMode: .inline)
    }
  }
}

#Preview {
  TestListView()
}

上記を実行すると、まず最初の画面(つまりTestListView)は次のように表示されます。

 

例として、3番目のセルを左へスワイプすると、次のように編集ボタンが表示されます。

 

編集ボタンを押すと、次のように編集画面(EditSheet)が表示されます。

 

ここは例として、nameを”hello”に変更し、descriptionを”world”に変更します。

 

編集画面を下にスワイプすると、編集画面が消えて元のリスト画面が表示されます。

次のように、3番目のセルは”Hello World”に変わっていることを確認できます。

 

 

解説

元ネタは参考サイトほぼそのままですが、ここは少し整理しただけです。

実装うまいなと思った点を簡単に説明します。

  1. どのセルが押されたかを判定するために、変数としてrowIDを持ってます。
    そして、①のようにBinding<bool>のgetとsetをカスタマイズして判定するようにしています。
  2. リスト画面から編集画面は②の$rowのように参照渡ししています。
    編集画面はその参照でもらったデータの属性をそのままTextFieldに渡してます。
    そうすると、TextFieldの値を変更すると、元のリスト画面にあるrows配列をそのまま変えられてしまう仕組みです。

リスト実装の参考になると嬉しいです。

参考

  1. Update row in list view from sheet in SwiftUI

投稿日

カテゴリー:

投稿者:

タグ:

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です