SwiftUI - Listの使い方

1. リストの使い方

alt

ここではSwiftUIのList{...}の使い方についてまとめておこうと思います。使い方はList{...}の中に出力したいものを書けば設定されたデフォルトスタイルで出力してくれます。デフォルトスタイルは画像のように左側に少し余白があるような設定のようです。

var body: some View {
  List {
    Text("List Item")
    Text("List Item")
    Text("List Item")
  }
}

2. 配列で出力

let Arr = ["List Item", "List Item", "List Item"]

var body: some View {
  List(0..<Arr.count) { item in
    Text(Arr[item])
  }
}

0..<X - 0からX未満

3. 配列のインデックス番号を表示する

配列のインデックス番号を表示させたい場合、下記のようにすると文字の左側に数字が表示されます。

let Arr = ["List Item", "List Item", "List Item"]

var body: some View {
  List(0..<Arr.count) { item in
    Text(String(item)) //<<追加
    Text(Arr[item])
  }
}

4. リストにタイトルを表示する

alt

リストにタイトルを表示するには、NavigationView {...}内でList {...}.navigationTitle("xxxx")を追加すると画像のようなタイトルが表示されます。

struct Fruit: Identifiable {
  let name: String
  let id = UUID()
}
private var fruits = [
  Fruit(name: "Apple"),
  Fruit(name: "Orange"),
  Fruit(name: "Grape")
]

var body: some View {
  NavigationView {
    List(fruits) {
      Text($0.name)
    }
    .navigationTitle("Fruit")
  }
}

Identifiable - idという変数を持っていること示すプロトコル
UUID() - ユニークidを自動生成してくれるもの
$0 - 引数名の省略

5. リストタイトルのスタイルを変更する

alt

var body: some View {
  NavigationView {
    List(fruits) {
      Text($0.name)
    }
    .navigationTitle("Fruit")
    .navigationBarTitleDisplayMode(.inline) //<<追加
  }
}

6. リストを選択できるようにする

alt

List(selection: x)でリストに選択機能が追加されるようですが、そのままでは選択ボタンは表示されません。このコードではtoolbar { EditButton() }で編集ボタンを追加してそのボタンをクリックすると選択できるようになります。はじめから選択ボタンを表示させたい場合は、.environment(\.editMode, .constant(.active))を追加すると表示されます。

struct Fruit: Identifiable, Hashable {
  let name: String
  let id = UUID()
}
private var fruits = [
  Fruit(name: "Apple"),
  Fruit(name: "Orange"),
  Fruit(name: "Grape")
]

@State private var multiSelection = Set<UUID>() //<<追加

var body: some View {
  NavigationView {
    //vv追加 
    List(fruits, selection: $multiSelection) {
      Text($0.name)
    }
    .navigationTitle("Fruit")
    .toolbar { EditButton() } //<<追加
  }
}

Set - 一意の要素で順序付けられていない場合、配列の代わりに使用する
Hashable - Hasher整数ハッシュ値を生成できる型。ハッシュとは、アルゴリズムを適用してデータ項目を値に変換するプロセス。Setデータ型の要素は、Hashableである必要がある。

参照: What Is Hashable in Swift?. A deep dive into the Hashable protocol… | by Yong Cui | Better Programming

7. 多次元リストとセクション

alt

このコードは公式ドキュメントのコードを参照してコンパクトにしてみたものですが、下記のように記述すると多次元リストを作成できるようです。セクション分けは、Section(){...}の部分です。

struct Food: Identifiable {
  let name: String
  let id = UUID()
}

struct Category: Identifiable {
  let name: String
  let food: [Food]
  let id = UUID()
}

private let category: [Category] = [
  Category(name: "Fruit",
    food: [
      Food(name: "Apple"),
      Food(name: "Orange"),
      Food(name: "Grape")
    ]
  ),
  
  Category(name: "Vegetables",
    food: [
      Food(name: "Tomato"),
      Food(name: "Carrot")
    ]
  )
]

var body: some View {
  NavigationView {
    List {
      ForEach(category) {cat in
        Section(header: Text("\(cat.name)")) {
          ForEach(cat.food) {food in
            Text(food.name)
          }
        }
      }
    }
    .navigationTitle("Food")       
  }
}

8. リストのスタイルを変更する

alt

var body: some View {
  NavigationView {
    List {
      ...
    }
    .navigationTitle("Food")
    .listStyle(GroupedListStyle()) //<<追加
  }
}

alt

var body: some View {
  NavigationView {
    List {
      ...
    }
    .navigationTitle("Food")
    .listStyle(InsetGroupedListStyle()) //<<変更  
  }
}

9. 階層リスト

alt

このコードも公式ドキュメントのコードを分かりやすくするために少し削ったものです。List(selection: x)と同じでList(children: x)で階層リストが出力しているようです。

struct FileItem: Hashable, Identifiable, CustomStringConvertible {
  var id: Self { self }
  var name: String
  var children: [FileItem]? = nil
  var description: String {
    switch children {
    case nil:
      return "📄 \(name)"
    case .some(let children):
      return children.isEmpty ? "📂 \(name)" : "📁 \(name)"
    }
  }
}
let fileHierarchyData: [FileItem] = [
  FileItem(name: "folder1", children:
    [
      FileItem(name: "folder1-1", children:
      [
        FileItem(name: "file1.jpg"),
        FileItem(name: "file2.jpg")
      ]),
    ]
  ),
  FileItem(name: "folder2", children:
    [
      FileItem(name: "file1.jpg")
    ]
  ),
]
var body: some View {
  List(fileHierarchyData, children: \.children) { item in
    Text(item.description)
  }
}

CustomStringConvertible - カスタマイズされたテキスト表現を持つ型
case .some(let x) - 関連づけられた値の一致パターン
.isEmpty - 文字列が空かどうかブール値を返す

List | Apple Developer Documentation