[SwiftUI] List の選択結果を活用する

SwiftUI2021

SwiftUI のリストで選択した要素を使った例を説明します。

環境&対象

以下の環境で動作確認を行なっています。

  • macOS Monterery beta 5
  • Xcode 13 beta5
  • iOS 15 beta

SwiftUI の List

SwiftUI の List は、要素をリスト表示する機能に加えて、要素を選択する機能も持っています。

List で要素をリスト表示

SimpleList
SimpleList

struct ContentView: View {
    @State private var listElements = ["First", "Second", "Third", "Forth"]
    var body: some View {
        VStack {
            GroupBox("List") {
                List(listElements, id: \.self) { element in
                    Text(element)
                }
            }
            .padding()
    }
}

List で要素を選択

List は、リスト表示に加えて要素を選択する機能も持っています。

SelectableList
SelectableList

選択表示は、iOS, macOS でそれぞれのプラットフォームに応じた表示になります。

単数選択か複数選択かは、List に与える引数で制御することができます。

具体的には、selection 引数に Optional 型の変数を指定すると 単数選択を指定することになり、Set 型の変数を指定すると複数選択できるよう指定することになります。

以下のコードは複数選択できるように、Set を引数に与えています。


struct ContentView: View {
    @Environment(\.editMode) var editMode
    @State private var listElements = ["First", "Second", "Third", "Forth"]
    @State private var selection: Set<String> = Set()
    var body: some View {
        VStack {
            GroupBox("List") {
                List(listElements, id: \.self, selection: $selection) { element in
                    Text(element)
                }
            }
        }
        .onAppear {
            editMode?.wrappedValue = .active
        }
        .padding()
    }
}

選択結果を参照する

単数選択

selection には、Optional 型を渡すと 単数選択になります。

何も選択していない状態では、nil がセットされ、選択されていればその要素がセットされています。


//
//  ContentView.swift
//
//  Created by : Tomoaki Yagishita on 2021/08/26
//  © 2021  SmallDeskSoftware
//

import SwiftUI
import SwiftUIDebugUtil

struct ContentView: View {
    @Environment(\.editMode) var editMode
    @State private var listElements = ["First", "Second", "Third", "Forth"]
    @State private var selectedOne: String? = nil
    var body: some View {
        VStack {
            GroupBox("List") {
                List(listElements, id:\.self, selection: $selectedOne) { element in
                    Text(element)
                }
            }
            .onAppear {
                editMode?.wrappedValue = .active
            }
            GroupBox("Selection") {
                Text("Selection: \(selectedOne == nil ? "None" : selectedOne!)")
            }
            .frame(minHeight: 300)
        }
            .padding()
    }
}
OneItemSelection
OneItemSelection

複数選択

複数アイテムの場合は、Set 型に 選択された要素の情報が保存されています。


//
//  ContentView.swift
//
//  Created by : Tomoaki Yagishita on 2021/08/26
//  © 2021  SmallDeskSoftware
//

import SwiftUI
import SwiftUIDebugUtil

struct ContentView: View {
    @Environment(\.editMode) var editMode
    @State private var listElements = ["First", "Second", "Third", "Forth"]
    @State private var selection: Set<String> = Set()
    var body: some View {
        VStack {
            GroupBox("List") {
                //EditButton()
                List(listElements, id: \.self, selection: $selection) { element in
                    Text(element)
                }
            }
            .onAppear {
                editMode?.wrappedValue = .active
            }
            GroupBox("Selection") {
                ForEach(Array(selection), id: \.self) { selected in
                    Text(selected)
                }
            }
            .frame(minHeight: 300)
        }
            .padding()
    }
}
MultiItemSelection
MultiItemSelection

まとめ:List での選択要素

List での選択要素
  • 単数選択であれば、Optional 形で selection: に渡す
  • 複数選択であれば、Set 形で selection: に渡す
  • iOS/iPadOS では、editMode を制御しないと選択可能にならない

説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。

2 COMMENTS

たまごっち

参考にさせていただいております。
TodoListを応用してチェックリスト及び結果ページを作成しプリンターでプリントアウトできるアプリを作成しております。
こちらの内容で複数選択をTextとして表示でき、また別ページの結果Viewへ反映することまでできました。
CoreDataを用いてデータ保存もやりたいと思っております。
そこで質問なのですが、こちらのページで紹介されているようにSet型にしたものをCoreDataで保存する際、Cannot assign value of type ‘Set’ to type ‘String’このようなエラーがでてどうしたらいいか悩んでおります。
よろしければ教えていただければ幸いです。
コメント欄へこのような質問を行なっていいのかわからなかったのですが藁をも掴む思いでさせていただきました。
不都合があるようでしたら大変申し訳ありません。

返信する
tyagishi

こんにちは。

書いていただいている情報だけではいろいろと原因が考えられるので、解決策を提示することは難しいです。
(意味的には、String 型の変数(?) に Set 型の情報を設定しようとしているのでエラー と言う内容ですが・・・)

途中までで書きかけになっていますが、この記事が参考になるかもしれません

他には 直接の回答ではありませんが、SwiftUI と CoreData を使って、MVVM というアーキテクチャパターンで TODO アプリを作る記事を書いているので、参考になる箇所があるかもしれません。
MVVM に焦点をあてているので、CoreData の説明はあまりなく、全15回と 少し長いですが、記事へのリンクはこちらです。

返信する

コメントを残す

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