見出し画像

Compose custom layouts with SwiftUI

Grid

グリッドレイアウトを簡単に組めるようになった。既にLazy Gridsがあるが、Viewが必要な時にロードされるので、大量なViewを扱うスクロールレイアウトに有効。しかし、サイズが不定になる方向があるので、初期化時に情報を渡す必要がある。一方で、新しいGridを使えば、固定のグリッドレイアウトならば簡単に組める。

Grid {
            
      GridRow {
          Color.red
              .gridCellColumns(2)
          Grid{
              GridRow{
                  Color.orange
              }
              GridRow{
                  Color.black
              }
              GridRow{
                  Color.purple
              }
          }
      }

      GridRow {
          Color.green
          Color.blue
      }

      GridRow {
          Color.yellow
              .gridCellColumns(3)
      }

}

Layout

カスタムレイアウトを組むことができるプロトコル(公式ドキュメント)

  • 等幅なサブビューを配置するレイアウト(HStack, VStackだとラップしたサイズになってしまう)

  • 円形にサブビューを配置するレイアウト

struct MyEqualWidthHStack: Layout {
    // レイアウトコンテナがサブビューを表示するのに必要なサイズを返却する
    func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout Void) -> CGSize {
        ...
    }

    // サブビューをコンテナに配置する
    func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout Void) {
        ...
    }
}

他にもこんなカスタムレイアウトが

ViewThatFits

A view that adapts to the available space by providing the first child view that fits.

表示可能領域で表示できる最初のChild Viewを表示する。

AnyLayout

A type-erased instance of the layout protocol.

Layoutプロトコルを型消去できるので、サブビューの状態を破壊することなく、レイアウトを動的に変更できる。

struct DynamicLayoutExample: View {
    @Environment(\.dynamicTypeSize) var dynamicTypeSize

    var body: some View {
        let layout = dynamicTypeSize <= .medium ? AnyLayout(HStack()) : AnyLayout(VStack())

        layout {
            Text("First label")
            Text("Second label")
        }
    }
}

実装例

公式ドキュメント

この記事が気に入ったらサポートをしてみませんか?