List では行の選択機能を実装できます。単一選択と複数選択の両方に対応しており、ファイル管理アプリやメールアプリのような UI を構築できます。
単一選択
単一の行を選択する場合は、選択中の ID を保持する @State 変数を用意し、selection パラメータにバインディングを渡します。
struct ContentView: View { let fruits = ["りんご", "みかん", "バナナ", "ぶどう"] @State private var selectedFruit: String? var body: some View { List(fruits, id: \.self, selection: $selectedFruit) { fruit in Text(fruit) } } }
選択された行は自動的にハイライトされます。選択を解除するには、同じ行をもう一度タップするか、selectedFruit = nil を設定します。
複数選択
複数の行を選択する場合は、Set を使います。
struct ContentView: View { let items = ["項目A", "項目B", "項目C", "項目D", "項目E"] @State private var selectedItems: Set<String> = [] var body: some View { NavigationStack { List(items, id: \.self, selection: $selectedItems) { item in Text(item) } .navigationTitle("選択: \(selectedItems.count)件") .toolbar { EditButton() } } } }
複数選択を有効にするには、通常 EditButton で編集モードに入る必要があります。
選択状態に応じた処理
選択されたアイテムに対して一括操作を行う例です。
struct FileListView: View { @State private var files = ["書類A.pdf", "書類B.pdf", "画像.png", "動画.mp4"] @State private var selectedFiles: Set<String> = [] var body: some View { NavigationStack { VStack { List(files, id: \.self, selection: $selectedFiles) { file in Label(file, systemImage: iconForFile(file)) } if !selectedFiles.isEmpty { HStack { Button("削除") { files.removeAll { selectedFiles.contains($0) } selectedFiles.removeAll() } .foregroundColor(.red) Spacer() Button("共有") { // 共有処理 } } .padding() } } .toolbar { EditButton() } } } func iconForFile(_ name: String) -> String { if name.hasSuffix(".pdf") { return "doc.fill" } if name.hasSuffix(".png") { return "photo" } if name.hasSuffix(".mp4") { return "video" } return "doc" } }
単一選択
Optional 型(例: String?)を使用。nil で選択なしを表す。
複数選択
Set 型(例: Set<String>)を使用。空の Set で選択なしを表す。
Identifiable な型での選択
カスタム型を使う場合は、id の型を selection の型に合わせます。
struct Item: Identifiable { let id = UUID() var name: String } struct ContentView: View { let items = [Item(name: "A"), Item(name: "B"), Item(name: "C")] @State private var selectedID: UUID? var body: some View { List(items, selection: $selectedID) { item in Text(item.name) } } }
編集モードなしでの選択
iOS 16 以降では、編集モードでなくても複数選択を可能にする方法があります。
struct ContentView: View { let items = ["A", "B", "C", "D"] @State private var selected: Set<String> = [] var body: some View { List(items, id: \.self) { item in HStack { Image(systemName: selected.contains(item) ? "checkmark.circle.fill" : "circle") .foregroundColor(selected.contains(item) ? .blue : .gray) Text(item) } .contentShape(Rectangle()) .onTapGesture { if selected.contains(item) { selected.remove(item) } else { selected.insert(item) } } } } }
この方法では標準の selection 機能を使わず、タップジェスチャーと状態管理で独自に実装しています。より細かいカスタマイズが可能です。