教育148875 views
高校化学2913383 views
LaTeX957300 views
高校物理158224 views
小学算数1194618 views
中学社会667106 views
いろは2986023 views
高校国語785655 views
Computer365120 views
小学社会308636 views
Help
Tools

English

選択モード(selection)

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 機能を使わず、タップジェスチャーと状態管理で独自に実装しています。より細かいカスタマイズが可能です。