【SwiftUI】Listの機能 – selectionでセルの単体選択、複数選択

List

今回はListの機能の一つである、セルの選択方法について説明します。

環境

  • Xcode12.5.1
  • iOS14.6
  • スクショはiPhone12Pro Maxで撮影

初めに

条件は前回の記事【SwiftUI】Listの機能 – 行の並べ替え、削除 と同じです。

Listの基本的な実装方法は本記事では説明しません。とは言えコードは記載しますし、List自体は非常に簡単に実装できると思います。
また、ListForEachで一覧表示を実装していること、ForEachでは更新可能な配列を使用しておりidを用いて識別されることが前提となります。

今回説明に使用するコードはこちらです。Personは必ずHashableに準拠するようにしてください。理由については今度詳しく説明します。

struct Person: Hashable{
    var name: String
    var age: Int
}

struct ContentView: View {
    @State private var people = [Person(name: "John", age: 18),
                                 Person(name: "Bob", age: 20),
                                 Person(name: "Tony", age: 35),
                                 Person(name: "Andy", age: 31)]
    
    var body: some View {
        VStack {
            List {
                ForEach(people, id: \.self) { person in
                    Text("\(person.name) : \(person.age)")
                }
            }
        }
    }
}

selectionを使う前に

selectionを使う前に、Listを編集可能な状態にするための準備が必要です。方法は2つあります。
1つは環境値.environmentを使って編集状態にする方法。
もう1つはEditButton()を設置する方法です。

.environmentを使った方法

struct Person: Hashable{
    var name: String
    var age: Int
}

struct ContentView: View {
    @State private var people = [Person(name: "John", age: 18),
                                 Person(name: "Bob", age: 20),
                                 Person(name: "Tony", age: 35),
                                 Person(name: "Andy", age: 31)]
    
    var body: some View {
        VStack {
            List {
                ForEach(people, id: \.self) { person in
                    Text("\(person.name) : \(person.age)")
                }
            }
            .environment(\.editMode, .constant(.active))
        }
    }
}

Listのモディファイアとして.environment(.editMode, .constant(.active))をつけてあげるだけです。こうするとListは常に編集可能な状態になります。

EditButton()を設置する方法

struct Person: Hashable{
    var name: String
    var age: Int
}

struct ContentView: View {
    @State private var people = [Person(name: "John", age: 18),
                                 Person(name: "Bob", age: 20),
                                 Person(name: "Tony", age: 35),
                                 Person(name: "Andy", age: 31)]
    
    var body: some View {
        VStack {
            EditButton()
            List {
                ForEach(people, id: \.self) { person in
                    Text("\(person.name) : \(person.age)")
                }
            }
        }
    }
}

レイアウトのどこかにEditButton()を置くだけです。こうするとボタンが表示され、そのボタンをタップするとListを編集可能な状態になります。

selectionを使った単体選択

まずは、選択したセルの情報を保持する変数selectedValueを用意します。今回はPerson型のデータをForEachで回して表示しているので、保持する変数もPerson型にします。このForEachで回すデータの型と選択したデータを保持する変数の型が一致していないと正しく動作しないので気をつけてください。

struct Person: Hashable{
    var name: String
    var age: Int
}

struct ContentView: View {
    @State private var people = [Person(name: "John", age: 18),
                                 Person(name: "Bob", age: 20),
                                 Person(name: "Tony", age: 35),
                                 Person(name: "Andy", age: 31)]
    @State private var selectedValue: Person?
    
    var body: some View {
        VStack {
            List {
                ForEach(people, id: \.self) { person in
                    Text("\(person.name) : \(person.age)")
                }
            }
            .environment(\.editMode, .constant(.active))
        }
    }
}

次に、Listのイニシャライザでselectionを指定します。引数には上で用意した変数selectedValueを設定します。

struct Person: Hashable{
    var name: String
    var age: Int
}

struct ContentView: View {
    @State private var people = [Person(name: "John", age: 18),
                                 Person(name: "Bob", age: 20),
                                 Person(name: "Tony", age: 35),
                                 Person(name: "Andy", age: 31)]
    @State private var selectedValue: Person?
    
    var body: some View {
        VStack {
            List(selection: $selectedValue) {
                ForEach(people, id: \.self) { person in
                    Text("\(person.name) : \(person.age)")
                }
            }
            .environment(\.editMode, .constant(.active))
        }
    }
}

こうするだけでリストの左側に選択マークが表示され、セルの選択が可能になります。

これで選択したデータはselectedValueに渡されるので、selectedValueを使って色々と処理ができます。例として、選択中のデータのnameを表示するようにしてみましょう。VStack の中に Text("選択:\(selectedValue?.name ?? "")")を追加します。

struct Person: Hashable{
    var name: String
    var age: Int
}

struct ContentView: View {
    @State private var people = [Person(name: "John", age: 18),
                                 Person(name: "Bob", age: 20),
                                 Person(name: "Tony", age: 35),
                                 Person(name: "Andy", age: 31)]
    @State private var selectedValue: Person?
    
    var body: some View {
        VStack {
            Text("選択:\(selectedValue?.name ?? "")")
            List(selection: $selectedValue) {
                ForEach(people, id: \.self) { person in
                    Text("\(person.name) : \(person.age)")
                }
            }
            .environment(\.editMode, .constant(.active))
        }
    }
}

選択したデータのnameが表示されるようになりました。

複数選択する方法

複数選択する場合は、selectedValueSet<>型にする必要があります。

Set<>型とは配列のようなもので、ユニークなデータしか保持しないため、同じデータを追加しようとしても追加されない特徴があります。また、データの順番という概念もありません。

struct Person: Hashable{
    var name: String
    var age: Int
}

struct ContentView: View {
    @State private var people = [Person(name: "John", age: 18),
                                 Person(name: "Bob", age: 20),
                                 Person(name: "Tony", age: 35),
                                 Person(name: "Andy", age: 31)]
    @State private var selectedValue: Set<Person> = []
    
    var body: some View {
        VStack {
            Text("\(selectedValue.count)")
            List(selection: $selectedValue) {
                ForEach(people, id: \.self) { person in
                    Text("\(person.name) : \(person.age)")
                }
            }
            .environment(\.editMode, .constant(.active))
        }
    }
}

このようにselectedValueSet<Person>という型にすることで、複数選択が可能になります。

今回は以上です。UIKitのUITableViewに比べて非常にシンプルな実装になりましたよね。

コメント