[SwiftUI][macOS] HSplitView と VSplitView の使い方

SwiftUI

     
⌛️ < 1 min.
SwiftUI で macOS 向けにのみ用意されている HSplitView と VSplitView の使い方を説明します。

環境&対象

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

  • macOS Big Sur 11.3 beta
  • Xcode 12.4

HSplitView, VSplitView

SwiftUI では macOS 向けにのみ HSplitView と VSplitView が用意されています。

その名前の通り、HSplitView が水平方向に分割するビューで、VSplitView が垂直方向に分割するビューです。

水平方向に並べるビュー HStack や 垂直方向に並べるビュー VStack と違い、分割位置に Divider が表示され、ユーザーが操作することで、分割位置を移動させることができます。

以下は、HSplitView を使った例です。

HSplitView example


struct ContentView: View {
    var body: some View {
        HSplitView {
            Rectangle()
                .fill(Color.red)
            Rectangle()
                .fill(Color.green)
        }
    }
}

VSplitView は、分割方向が垂直方向になったもので、方向以外は、HSplitView と同様の動きをします。

Apple の Document はおかしいです

HSplitView と VSplitView のドキュメントは、それぞれ こちらこちら なんですが、なにやら、fileExporter… というようなインスタンスメソッドが定義されていると説明されています。

ですが、公開されている SwiftUI のファイルを見る限りでは、特にメソッドが用意されているようには見えません。・・・用意されていても、使い道がわかりませんし。

Tips: SplitView を使う時の工夫

SplitView を使うと気付くのですが、すこし使い方に工夫が必要です。

SplitView の内部のビューが、いわゆる push-out タイプのビューであれば、期待通りに動作します。
しかし、pull-in タイプのビューであれば、期待通りにならない時が発生します。

最初に提示した例は、Rectangle を使っていました。Rectangle は push-out タイプのビューですので、きれいに(?)分割されて マウス操作で分割位置も移動させることができます。

以下は、pull-in タイプのビューを使った例です。(pull-in タイプのビューとして、Text を使用しています。)

HSplitView with pull-in


struct ContentView: View {
    var body: some View {
        HSplitView {
            Text("Left Pane")
                .background(Color.red)
            Text("Right Pane")
                .background(Color.green)
        }
        .frame(width: 300, height: 300)
    }
}

pull-in タイプのビューと組み合わせたときの課題

おそらくですが、SplitView は、あくまで子ビューの持つ表示領域内でのみ 分割位置を調整できるようになっています。(普通そうします・・・)

Push-out であれば 可能な限り広く領域を確保するので、SplitView の調整領域は広くなりますが、pull-in のときは 必要最小限の領域しか確保しないので、上のような動作になってしまいます。

なお、Right Pange の方に分割位置を移動できない理由は、Left Pane が最大に確保できる領域は Text が確保できる領域であり、それ以上に広げるような動作が許容されていないからです。

上記は、.frame 指定を外して動作させたときに、分割位置を左に移動させると ウィンドウ自体が小さくなることからの推測です。

このような動作が期待する動作である時もあるでしょうが、SplitView の内部に配置したいビューが push-out / pull-in のいずれでも同じように動作させたい時が多そうな気がします。

SplitView を pull-in タイプと組み合わせて使う

Pull-in タイプのビューを push-out にする 簡単な方法は、 GeometryReader でラップすることです。

以下のようにすることで、Rectangle(push-out タイプ) と Text(pull-in タイプ) を同じように操作させることが可能になります。

HSplitView with pull-in/push-out mixed


struct ContentView: View {
    var body: some View {
        HSplitView {
            GeometryReader { geom in
                Text("Left Pane")
                    .frame(width: geom.size.width, height: geom.size.height)
                    .background(Color.red)
            }
            Rectangle()
                .fill(Color.green)
        }
        .frame(width: 300, height: 300)
    }
}

まとめ:HSplitView/VSplitView の上手な使い方

HSplitView/VSplitView の上手な使い方
  • HSplitView/VSplitView は、子ビューの領域内でのみ分割位置を調整可能
  • pull-in ビューを子ビューに使うと、子ビューが使用する最小限の領域のみで調整可能となるのがデフォルト動作
  • pull-in ビューを子ビューに使うときは、Geometry Reader でラップすると push-out 的に使用できる

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

2 COMMENTS

Harumaru

一見意味がないように見えるGeometryReaderの使用によってレイアウトを調整するテクニックが役に立ちました!他のサイトにはこのようにSwiftUIのレイアウトについて詳しく載っていませんでした。すごいです。

返信する
tyagishi

コメントありがとうございます。

実は、.frame(maxWidth:.infinity, maxHeight:.infinity) だけでもいけたりします(汗)。SwiftUI のレイアウトを理解するポイントの1つは、push-out/pull-in を理解することだと思っていて、いくつか記事を書いていますので、参考にしていただけると嬉しいです。リンクはこちらです。

返信する

コメントを残す

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