[SwiftUI] DisclosureGroup を 行のどこをクリックしても、Expand させる方法

SwiftUI

SwiftUI の DisclosureGroup を 右矢印以外の箇所でも Expand を切り替える方法を説明します。

環境&対象

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

  • macOS Big Sur 11.2.3
  • Xcode 12.4
  • iOS 14.4

DisclosureGroup

クリックにより、開閉するリストを作る時に使います。

Apple のドキュメントは、こちら

多くの要素があるリストを表示する時でも、一部要素を隠すことができるので、リスト全体を俯瞰することが容易になります。

画面スナップショット

閉じた状態
閉じた状態
開いた状態
開いた状態

DisclosureGroup を使ったコード

以下が、上記アプリの実装コードです。

ContentView

struct ContentView: View {
    var body: some View {
        VStack {
            DisclosureGroup(
                content: {
                    Text("Content1")
                    Text("Content2")
                    Text("Content3")
                    Text("Content4")
                    Text("Content5")
                },
                label: {
                Text("Label")
                }
            )
        }
        .padding()
    }
}

標準の DisclosureGroup の開閉方法

DisclosureGroup は、ラベル右に表示される > をクリックすることで、開閉が行われます。

ラベル自体をクリックしても、開閉は行われません。

使用ケースによっては、ラベルをクリックしても開閉できた方が便利な時があるので、その方法を説明します。

DisclosureGroup の開閉方法を追加

DisclosureGroup の init を調べてみると、isExpanded という引数ラベルを持つものがあります。

Binding<Bool> 型のこの変数を制御することで、プログラム的に DisclosureGroup の開閉を制御することができます。

# この変数を使うことで開いた状態を初期状態にすることもできます。

ラベルクリックで開閉を制御するために、この仕組みを使用します。

ラベル定義と .onTapGesture

ラベル定義を行なった時に、.onTapGesture を指定することで、そのラベルがクリックされた時の動作を指定することができます。

Label定義内部の Text と .onTapGesture

Text("Label")
    .onTapGesture {
        // tap 時の動作
    }

ラベルクリックで開閉する実装

isExpand を持つ init を使った DiclosureGroup と .onTapGesture を使った Label を組み合わせたコードは、以下です。

ContentView

struct ContentView: View {
    // (1)
    @State private var expand = false
    var body: some View {
        VStack {
            DisclosureGroup(
                // (2)
                isExpanded: $expand,
                content: {
                    Text("Content1")
                    Text("Content2")
                    Text("Content3")
                    Text("Content4")
                    Text("Content5")
                },
                label: {
                    Text("Label")
                        // (3)
                        .onTapGesture {
                            // (4)
                            expand.toggle()
                        }
                     }
            )
        }
        .padding()
    }
}
コード解説
  1. isExpanded に使用する Bool 変数を用意します
  2. isExpanded を使った init で DisclosureGroup を使用します
  3. .onTapGesture を設定することで、Text をクリックした時の動作を設定します
  4. クリックされた時に、expand を toggle することで、DisclosureGroup の開閉を制御します

行全体をクリックに反応させる方法

ここまでの実装でテキストをクリックしても、DisclosureGroup が開閉するようになりました。

便利にはなったのですが、テキストが短い時にクリックが難しいかもしれません。

以下のようにすると、行全体がクリック対象となります。

行全体をクリック対象にするコード

Text("Label")
    .frame(maxWidth: .infinity, alignment: .leading)
    .contentShape(Rectangle())
    .onTapGesture {
        expand.toggle()
    }
.frame で行をいっぱいまで横に広げてつつ 左寄せで表示するようにしています。
その後、.contentShape で矩形を指定することで行全体がクリック対象となります。

まとめ:DisclosureGroup の開閉を行のどこをクリックしてもできるようにする方法

DisclosureGroup の開閉を行のどこをクリックしてもできるようにする方法
  • isExpanded を指定できる init で DisclosureGroup を設定する
  • .onTapGesture で isExpanded を制御することで、クリックによる開閉制御を行う
  • .frame と .contentShape を組み合わせることで、行のどこをクリックしても反応できるようにする

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

コメントを残す

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