[SwiftUI] OutlineGroup と DisclosureGroup

SwiftUI2021

     

TAGS:

⌛️ 2 min.
SwiftUI を使って、階層構造を持つデータの表示方法を説明します。

環境&対象

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

  • 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

コードを見るとそのままですが、最上位の 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

OutlineGroupとDisclosureGroup の異なる点は、以下です。
・指定された KeyPath を使用して子要素へ ”再帰的に”アクセスする
・子要素にさらに子要素があると判断すると 階層的に DisclosureGroup を作成する

つまり、OutlineGroup は、必要に応じて階層的な DisclosureGroup を作成してくれているということです。

expanded/collapsed

DisclosureGroup では、引数 isExpanded を使用することで開閉を制御できましたが、OutlineGroup には そのような option は、用意されていません。

開閉状態を制御する/保存するとが必要であれば、DisclosureGroup を使用して ビューを構築することが必要です。

まとめ

SwiftUI で 階層構造を持つデータを表現をするときに使用する DisclosureGroup と OutlineGroup を説明しました。

DisclosureGroup と OutlineGroup
  • DisclosureGroup は、1段の階層表現を行う
  • DisclosureGroup は、isExpanded 引数で、開閉状態を 取得/設定 できる
  • OutlineGroup は、子要素への KeyPath を使用して多段の階層表現ができる
  • OutlineGroup は、開閉状態を 取得/設定 することはできない
  • OutlineGroup は、内部では DisclosureGroup を使用している

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

SwiftUI おすすめ本

SwiftUI を理解するには、以下の本がおすすめです。

# SwiftUI2.0 が登場したことで少し古くなってしまいましたが、いまでも 定番本です。

コメントを残す

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