Sponsor Link
環境&対象
- macOS Monterey 12.5 Beta
- Xcode 14.0 Beta3
- iOS 16.0 beta
SwiftUI での 階層表示向け View
SwiftUI では、以下の View を使うことで、階層的なデータ表示ができます。
– OutlineGroup
– DisclosureGroup
DisclosureGroup
DisclosureGroup は、View に(1段の)階層関係を持たせ、下位 View の 表示/非表示 を制御できるようにする View です。
以下は、Apple のサンプルコードです。
//
// ContentView.swift
//
// Created by : Tomoaki Yagishita on 2022/07/07
//
import SwiftUI
struct ContentView: View {
struct ToggleStates {
var oneIsOn: Bool = false
var twoIsOn: Bool = true
}
@State private var toggleStates = ToggleStates()
@State private var topExpanded: Bool = true
var body: some View {
DisclosureGroup("Items", isExpanded: $topExpanded) {
Toggle("Toggle 1", isOn: $toggleStates.oneIsOn)
Toggle("Toggle 2", isOn: $toggleStates.twoIsOn)
DisclosureGroup("Sub-items") {
Text("Sub-item 1")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
実行すると以下のような表示になります。
コードを見るとそのままですが、最上位の DisclosureGroup “Items” 配下に、3つの View (“Toggle 1”, “Toggle 2”, “Sub-items”)が配置されています。
3つの下位 View のうち “Sub-items” も DisclosureGroup であり、さらにその配下に “Sub-item 1” という View を持っています。
expanded/collapsed 制御
サンプルコードでは、DisclosureGroup “Items” を定義するときに、isExpanded 引数として、@Binding<Bool> を渡すことで、現在 expanded (開かれている) 状態 なのか collapsed (閉じられている) 状態なのか を設定/検知 することができます。
サンプルコードでは、topExpanded の初期値が true であるため、起動直後の DisclosureGroup “Items” は、expanded 状態になります。
なお、指定をしないと初期値は collapsed 状態です。
複数階層表現
DisclosureGroup 自体は、1段の階層を表現しますが、DisclosureGroup の子要素に さらに DisclosureGroup を持たせることで、多段の階層構造を表現することができます。
OutlineGroup
OutlineGroup は、階層的なデータをベースに 必要に応じて DisclosureGroup を作ってくれる View です。
以下のコードは、Apple のサンプルコードです。
//
// ContentView.swift
//
import SwiftUI
struct ContentView: View {
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 data =
FileItem(name: "users", children:
[FileItem(name: "user1234", children:
[FileItem(name: "Photos", children:
[FileItem(name: "photo001.jpg"),
FileItem(name: "photo002.jpg")]),
FileItem(name: "Movies", children:
[FileItem(name: "movie001.mp4")]),
FileItem(name: "Documents", children: [])
]),
FileItem(name: "newuser", children:
[FileItem(name: "Documents", children: [])
])
])
var body: some View {
OutlineGroup(data, children: \.children) { item in
Text("\(item.description)")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
データ用意のためのコードが増えていますが、実際に OutlineGroup を使用して ビューを定義している行は、var body 内の3行です。非常に簡単に使用できることがわかります。
実行すると、以下のような表示になります。
OutlineGroupとDisclosureGroup の異なる点は、以下です。
・指定された KeyPath を使用して子要素へ ”再帰的に”アクセスする
・子要素にさらに子要素があると判断すると 階層的に DisclosureGroup を作成する
つまり、OutlineGroup は、必要に応じて階層的な DisclosureGroup を作成してくれているということです。
expanded/collapsed
DisclosureGroup では、引数 isExpanded を使用することで開閉を制御できましたが、OutlineGroup には そのような option は、用意されていません。
開閉状態を制御する/保存するとが必要であれば、DisclosureGroup を使用して ビューを構築することが必要です。
まとめ
SwiftUI で 階層構造を持つデータを表現をするときに使用する DisclosureGroup と OutlineGroup を説明しました。
- DisclosureGroup は、1段の階層表現を行う
- DisclosureGroup は、isExpanded 引数で、開閉状態を 取得/設定 できる
- OutlineGroup は、子要素への KeyPath を使用して多段の階層表現ができる
- OutlineGroup は、開閉状態を 取得/設定 することはできない
- OutlineGroup は、内部では DisclosureGroup を使用している
説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。
SwiftUI おすすめ本
SwiftUI を理解するには、以下の本がおすすめです。
# SwiftUI2.0 が登場したことで少し古くなってしまいましたが、いまでも 定番本です。
Sponsor Link