Compose では、UI 要素は呼び出されたときに UI の一部を出力するコンポーズ可能な関数によって表され、画面上にレンダリングされる UI ツリーに追加されます。各 UI 要素には親が 1 つあり、場合によっては多くの子があります。各要素は、(x, y) 位置として指定された親内の場所に、width
および height
で指定されたサイズで配置されます。
親は子要素の制約を定義します。要素は、これらの制約内で自身のサイズを定義するように要求されます。制約により、要素の width
と height
の最小値と最大値が制限されます。要素に子要素がある場合、親の要素は、自身のサイズを判断しやすくするために、子のそれぞれを測定できます。要素が自身のサイズを決定して報告すると、カスタム レイアウトの作成で詳しく説明されているように、子要素を自身に対し相対的に配置する方法を定義できるようになります。
UI ツリー内の各ノードのレイアウトは、次の 3 つのステップで行います。各ノードは次のことを行う必要があります。
- すべての子を測定する
- ノード自体のサイズを決定する
- 子を配置する
スコープの使用により、子の測定と配置を行えるタイミングが決まります。レイアウトは測定パスとレイアウトパスの実行中のみ測定でき、子の配置はレイアウトパスの実行中に、測定した後でのみ行うことができます。この操作は、Compose スコープ(MeasureScope
や PlacementScope
など)によりコンパイル時に適用されます。
レイアウト修飾子を使用する
layout
修飾子を使用して、要素の測定方法と配置方法を変更できます。Layout
はラムダです。パラメータには、測定可能な要素(measurable
として渡される)と、そのコンポーザブルの定義された制約(constraints
として渡される)が含まれます。カスタム レイアウト修飾子は次のようになります。
fun Modifier.customLayoutModifier() = layout { measurable, constraints -> // ... }
画面に Text
を表示し、上端からテキスト先頭行のベースラインまでの距離を制御してみましょう。これは paddingFromBaseline
修飾子の動作とまったく同じです。ここでは、これを例として実装します。そのためには、layout
修飾子を使用して、コンポーザブルを画面に手動で配置します。Text
の上パディングを 24.dp
に設定した場合の望ましい動作は次のとおりです。
この間隔を生成するコードを次に示します。
fun Modifier.firstBaselineToTop( firstBaselineToTop: Dp ) = layout { measurable, constraints -> // Measure the composable val placeable = measurable.measure(constraints) // Check the composable has a first baseline check(placeable[FirstBaseline] != AlignmentLine.Unspecified) val firstBaseline = placeable[FirstBaseline] // Height of the composable with padding - first baseline val placeableY = firstBaselineToTop.roundToPx() - firstBaseline val height = placeable.height + placeableY layout(placeable.width, height) { // Where the composable gets placed placeable.placeRelative(0, placeableY) } }
このコードの流れは次のとおりです。
measurable
ラムダ パラメータでmeasurable.measure(constraints)
を呼び出して、測定可能なパラメータで表されるText
を測定します。layout(width, height)
メソッドを呼び出して、コンポーザブルのサイズを指定します。これにより、ラップされた要素の配置に使用するラムダも提供されます。この場合、最後のベースラインと追加された上パディングの間の高さです。placeable.place(x, y)
を呼び出して、ラップされた要素を画面に配置します。配置されていないと、ラップされた要素は表示されません。y
位置は上パディングと、テキストの最初のベースライン位置との差に対応します。
これが期待どおりに機能することを確認するには、Text
で次の修飾子を使用します。
@Preview @Composable fun TextWithPaddingToBaselinePreview() { MyApplicationTheme { Text("Hi there!", Modifier.firstBaselineToTop(32.dp)) } } @Preview @Composable fun TextWithNormalPaddingPreview() { MyApplicationTheme { Text("Hi there!", Modifier.padding(top = 32.dp)) } }
カスタム レイアウトを作成する
layout
修飾子は呼び出し元のコンポーザブルのみを変更します。複数のコンポーザブルを測定して配置するには、代わりに Layout
コンポーザブルを使用します。このコンポーザブルを使用することで、子を手動で測定して配置できます。Column
や Row
などの上位レベルのレイアウトはすべて、Layout
コンポーザブルで作成されます。
Column
の非常に基本的なバージョンを作成しましょう。ほとんどのカスタム レイアウトは、このパターンに従います。
@Composable fun MyBasicColumn( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( modifier = modifier, content = content ) { measurables, constraints -> // measure and position children given constraints logic here // ... } }
layout
修飾子と同様に、measurables
は測定する必要がある子のリストです。constraints
は親からの制約です。前と同じロジックに従って、MyBasicColumn
は次のように実装できます。
@Composable fun MyBasicColumn( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( modifier = modifier, content = content ) { measurables, constraints -> // Don't constrain child views further, measure them with given constraints // List of measured children val placeables = measurables.map { measurable -> // Measure each children measurable.measure(constraints) } // Set the size of the layout as big as it can layout(constraints.maxWidth, constraints.maxHeight) { // Track the y co-ord we have placed children up to var yPosition = 0 // Place children in the parent layout placeables.forEach { placeable -> // Position item on the screen placeable.placeRelative(x = 0, y = yPosition) // Record the y co-ord placed up to yPosition += placeable.height } } } }
子コンポーザブルは Layout
制約によって制約され(minHeight
で制約されていない場合)、前のコンポーザブルの yPosition
に基づいて配置されます。
カスタム コンポーザブルの使用方法は次のとおりです。
@Composable fun CallingComposable(modifier: Modifier = Modifier) { MyBasicColumn(modifier.padding(8.dp)) { Text("MyBasicColumn") Text("places items") Text("vertically.") Text("We've done it by hand!") } }
レイアウト方向
コンポーザブルのレイアウト方向を変更するには、LocalLayoutDirection
コンポジション ローカルを変更します。
コンポーザブルを手動で画面に配置する場合、LayoutDirection
は、layout
修飾子または Layout
コンポーザブルの LayoutScope
の一部になります。
layoutDirection
を使用する場合は、place
を使用してコンポーザブルを配置します。placeRelative
メソッドと異なり、place
はレイアウト方向(左から右 / 右から左)に基づいて変更されることはありません。
カスタム レイアウトの実例
レイアウトと修飾子の詳細については、Jetpack Compose でのレイアウトをご覧ください。また、カスタム レイアウトの実例については、カスタム レイアウトを作成する Compose サンプルをご確認ください。
詳細
Compose のカスタム レイアウトについて詳しくは、以下の参考情報をご覧ください。
動画
あなたへのおすすめ
- 注: JavaScript がオフになっている場合はリンクテキストが表示されます
- Compose レイアウトの固有の測定値
- Compose のグラフィック
- Compose 修飾子