Jetpack composeは、アプリ開発に必要な一通りのUIコンポーネントをライブラリで提供しています。
そのライブラリ中にUI要素を格納する機能をもつコンテナ型のUIがあります。
Column/Row/Boxがコンテナ型のUIです。構成や使用方法などをまとめます。
※環境:Android Studio Hedgehog | 2023.1.1 Patch 1
Kotlin 1.8.10
Compose Compiler 1.4.3
目次
コンテナ型のUI
自身の中に子UI要素を格納(配置)する機能をもつUI要素(Composable関数)があります。ここでは、それを「コンテナ型のUI」と呼ぶことにします。
次にあげるUI要素はコンテナ型のUIです。
| 関数 | 配置 |
|---|---|
| Column | 子UI要素を垂直に並べる![]() |
| Row | 子UI要素を水平に並べる![]() |
| Box | 子UI要素を子UI要素の上に配置![]() |
これ以外に、同等なUI要素としてLazyColumn/Row(リスト)・Lazy***Grid(グリッド)などもありますが、用法が異なるので、本記事では取り挙げません。

しかし、子UI要素のサイズと位置を考慮した、配置制御を行いません。コンテナというよりも、UI階層を伴った単なるグループ化です。
private val Red = Color(255, 0, 0, 30)
private val Green = Color(0, 255, 0, 30)
private val Blue = Color(0, 0, 255, 30)
private val Gray = Color(230, 230, 230, 255)
@Composable
fun ContainerFunc() {
Func {
Text(
text = "あいうえおん",
fontSize = 20.sp,
modifier = Modifier.background(color = Red)
)
Text(
text = "ABCD",
fontSize = 20.sp,
modifier = Modifier.background(color = Blue)
)
Text(
text = "#$",
fontSize = 20.sp,
modifier = Modifier.background(color = Green)
)
}
}
@Composable
fun Func(content: @Composable () -> Unit) {
content()
}

Column
ColumnはUI要素を垂直に並ならべるコンテナ型のUIです。子UI要素のサイズと位置を取得して配置します。
関数の引数
Columnの状態(コンテンツ、装飾、演出など)は、引数により指定できます。
@Composable
inline fun Column(
modifier: Modifier = Modifier,
verticalArrangement: Arrangement.Vertical = Arrangement.Top,
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
content: @Composable ColumnScope.() -> Unit
) { ... }
| 引数 | 概要 | |
|---|---|---|
| modifier | Modifier | UI全般のCompose修飾子 |
| verticalArrangement | Arrangement.Vertival | コンテンツの配置(垂直方向) デフォルト:Top |
| horizontalAlignment | Alignment.Horizontal | コンテンツの配置(水平方向) デフォルト:Start |
| contet | ColumnScope.() -> Unit | 格納するコンテンツ |
| 配置パラメータ | 概要 | |
|---|---|---|
| Alignment | CenterHorizontally | 水平方法の中央 |
| Start | 左端 | |
| End | 右端 | |
| Arrangement | Center | 垂直方向の中央 |
| Top | 上端 | |
| Bottom | 下端 | |
| SpaceAround | 空きスペースの均一化(後述) | |
| SpaceBetween | ||
| SpaceEvenly | ||
Columnの例
コンテンツ(子UI要素、Textが3つ)を中央に配置する例です。
@Composable
fun ContainerColumn() {
Column(
modifier =Modifier.background(color = Gray),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = "あいうえおん",
fontSize = 20.sp,
modifier = Modifier.background(color = Red)
)
Text(
text = "ABCD",
fontSize = 20.sp,
modifier = Modifier.background(color = Blue)
)
Text(
text = "#$",
fontSize = 20.sp,
modifier = Modifier.background(color = Green)
)
}
}

Row
RowはUI要素を水平に並ならべるコンテナ型のUIです。子UI要素のサイズと位置を取得して配置します。
関数の引数
Rowの状態(コンテンツ、装飾、演出など)は、引数により指定できます。
@Composable
inline fun Row(
modifier: Modifier = Modifier,
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
verticalAlignment: Alignment.Vertical = Alignment.Top,
content: @Composable RowScope.() -> Unit
) { ... }
| 引数 | 概要 | |
|---|---|---|
| modifier | Modifier | UI全般のCompose修飾子 |
| horizontalArrangement | Arrangement.Horizontal | コンテンツの配置(水平方向) デフォルト:Start |
| verticalAlignment | Alignment.Vertical | コンテンツの配置(垂直方向) デフォルト:Top |
| content | @Composable RowScope.() -> Unit | 格納するコンテンツ |
| 配置パラメータ | 概要 | |
|---|---|---|
| Alignment | CenterVertical | 垂直方向の中央 |
| Top | 上端 | |
| Bottom | 下端 | |
| Arrangement | Center | 水平方向の中央 |
| Start | 左端 | |
| End | 右端 | |
| SpaceAround | 空きスペースの均一化(後述) | |
| SpaceBetween | ||
| SpaceEvenly | ||
Rowの例
コンテンツ(子UI要素、Textが3つ)を中央に配置する例です。
@Composable
fun ContainerRow() {
Row(
modifier =Modifier.background(color = Gray),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "あいうえおん",
fontSize = 20.sp,
modifier = Modifier.background(color = Red)
)
Text(
text = "ABCD",
fontSize = 20.sp,
modifier = Modifier.background(color = Blue)
)
Text(
text = "#$",
fontSize = 20.sp,
modifier = Modifier.background(color = Green)
)
}
}

Box
Boxは子UI要素を子UI要素の上に配置するコンテナ型のUIです。子UI要素のサイズと位置を取得して配置します。
関数の引数
Boxの状態(コンテンツ、装飾、演出など)は、引数により指定できます。
@Composable
inline fun Box(
modifier: Modifier = Modifier,
contentAlignment: Alignment = Alignment.TopStart,
propagateMinConstraints: Boolean = false,
content: @Composable BoxScope.() -> Unit
) { ... }
| 引数 | 概要 | |
|---|---|---|
| modifier | Modifier | UI全般のCompose修飾子 |
| contentAlignment | Alignment | コンテンツの配置 デフォルト:TopStart |
| propagateMinConstraints | Boolean | |
| content | @Composable BoxScope.() -> Unit | 格納するコンテンツ |
| 配置パラメータ | 概要 | |
|---|---|---|
| Alignment | TopStart | (y、x)←(上端、左端) |
| TopCenter | (y、x)←(上端、水平方向の中央) | |
| TopEnd | (y、x)←(上端、右端) | |
| CenterStart | (y、x)←(垂直方向の中央、左端) | |
| Center | (y、x)←(垂直方向の中央、水平方向の中央) | |
| CenterEnd | (y、x)←(垂直方向の中央、右端) | |
| BottomStart | (y、x)←(下端、左端) | |
| BottomCenter | (y、x)←(下端、水平方向の中央) | |
| BottomEnd | (y、x)←(下端、右端) | |
Boxの例
コンテンツ(子UI要素、Textが3つ)を中央に配置する例です。
@Composable
fun ContainerBox() {
Box(
modifier =Modifier.background(color = Gray),
contentAlignment = Alignment.Center
) {
Text(
text = "あいうえおん",
fontSize = 20.sp,
modifier = Modifier.background(color = Red)
)
Text(
text = "ABCD",
fontSize = 20.sp,
modifier = Modifier.background(color = Blue)
)
Text(
text = "#$",
fontSize = 20.sp,
modifier = Modifier.background(color = Green)
)
}
}

関数の構成
コンテナ型のUIはLayout関数(Composable関数)のみで構成されます。
Layout関数は描画処理のLayoutフェーズで呼び出されて(Layout関数は定義のみ、実際の呼び出し先はmesurePolicyの関数)、UI要素のサイズや位置を算出します。
ドキュメントはLayout関数を「レイアウトノード」と呼んでいます。
※描画処理については「Jetpack Compose:Composeによるアプリ画面の描画」を参照
※レイアウトノードについては「制約と修飾子の順序」を参照
つまり、コンテナ型のUIは、子UI要素の配置しか行いません。
@Composable
inline fun Column(
modifier: Modifier = Modifier,
verticalArrangement: Arrangement.Vertical = Arrangement.Top,
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
content: @Composable ColumnScope.() -> Unit
) {
val measurePolicy = columnMeasurePolicy(
verticalArrangement, horizontalAlignment
)
Layout(
content = { ColumnScopeInstance.content() },
measurePolicy = measurePolicy,
modifier = modifier
)
}
@Composable
inline fun Row(
modifier: Modifier = Modifier,
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
verticalAlignment: Alignment.Vertical = Alignment.Top,
content: @Composable RowScope.() -> Unit
) {
val measurePolicy = rowMeasurePolicy(
horizontalArrangement, verticalAlignment
)
Layout(
content = { RowScopeInstance.content() },
measurePolicy = measurePolicy,
modifier = modifier
)
}
@Composable
inline fun Box(
modifier: Modifier = Modifier,
contentAlignment: Alignment = Alignment.TopStart,
propagateMinConstraints: Boolean = false,
content: @Composable BoxScope.() -> Unit
) {
val measurePolicy = rememberBoxMeasurePolicy(
contentAlignment, propagateMinConstraints
)
Layout(
content = { BoxScopeInstance.content() },
measurePolicy = measurePolicy,
modifier = modifier
)
}
@Suppress("ComposableLambdaParameterPosition")
@UiComposable
@Composable
inline fun Layout(
content: @Composable @UiComposable () -> Unit,
modifier: Modifier = Modifier,
measurePolicy: MeasurePolicy
) {
val compositeKeyHash = currentCompositeKeyHash
val localMap = currentComposer.currentCompositionLocalMap
ReusableComposeNode<ComposeUiNode, Applier<Any>>(
factory = ComposeUiNode.Constructor,
update = {
set(measurePolicy, SetMeasurePolicy)
set(localMap, SetResolvedCompositionLocals)
@OptIn(ExperimentalComposeUiApi::class)
set(compositeKeyHash, SetCompositeKeyHash)
},
skippableUpdate = materializerOf(modifier),
content = content
)
}
配置の方法(縦・横に並べる、重ねる)がLayout関数に与えられる引数measurePolicyで決められています。Column/Row/Boxの違いは、このmeasurePolicyの違いです。
weightによるサイズ指定
weightは子UI要素のサイズに重み付けをするCompose修飾子です。
コンテナ型のUIのサイズ(縦または横のサイズ)へピッタリと収まるように、重みに合った比率で子UI要素のサイズを分配します。
以下はRowのサンプルです。並びが縦になるだけで、Columnも同様です。
weightあり
重みに合った比率でサイズを分配します。
@Preview_mdpi
@Composable
fun ImagesList1() {
Row(modifier = Modifier.fillMaxWidth()) {
Image(
painterResource(R.drawable.azami60x60), // イメージサイズ:60x60[dp]
contentDescription = null,
contentScale = ContentScale.FillWidth,
modifier = Modifier.weight(3.0f)
)
Image(
painterResource(R.drawable.azami60x60),
contentDescription = null,
contentScale = ContentScale.FillWidth,
modifier = Modifier.weight(1.0f)
)
Image(
painterResource(R.drawable.azami60x60),
contentDescription = null,
contentScale = ContentScale.FillWidth,
modifier = Modifier.weight(2.0f)
)
}
}

weightなし
コンテンツのサイズ(Imageのサイズ)で表示するように努めます。
コンテナサイズ ≧ コンテンツ合計サイズデフォルトは左詰めで配置され、右側は空きます。
@Preview_mdpi
@Composable
fun ImagesList2_1() {
Row(modifier = Modifier.fillMaxWidth()) {
for(i in 0..2) {
Image(
painterResource(R.drawable.azami60x60), // イメージサイズ:60x60[dp]
contentDescription = null,
contentScale = ContentScale.FillWidth,
modifier = Modifier
)
}
}
}

コンテンツのサイズ(Imageのサイズ)で表示するように努めますが、端数(5番目のImage)が出た場合は、それがそのままコンテンツのサイズになります。
溢れてしまったコンテンツ(6番目のImage)は表示されません。
@Preview_mdpi
@Composable
fun ImagesList2_2() {
Row(modifier = Modifier.fillMaxWidth()) {
for(i in 0..6) {
Image(
painterResource(R.drawable.azami60x60), // イメージサイズ:60x60[dp]
contentScale = ContentScale.FillWidth,
contentDescription = null,
modifier = Modifier
)
}
}
}

weightあり・なし混合
先にweightなしのコンテンツのサイズを確保した後、残りを重みに合った比率で分配します。
@Preview_mdpi
@Composable
fun ImagesList3() {
Row(modifier = Modifier.fillMaxWidth()) {
Image(
painterResource(R.drawable.azami60x60), // イメージサイズ:60x60[dp]
contentDescription = null,
contentScale = ContentScale.FillWidth,
modifier = Modifier.weight(1.0f)
)
Image(
painterResource(R.drawable.azami60x60),
contentDescription = null,
contentScale = ContentScale.FillWidth,
modifier = Modifier.weight(2.0f)
)
Image(
painterResource(R.drawable.azami60x60),
contentDescription = null,
contentScale = ContentScale.FillWidth,
modifier = Modifier
)
}
}

特殊な配置(空きスペースの均一化)
子UI要素を配置した時に生まれる空きスペースを均一化することが出来ます。
例はColumnの場合ですが、均一化の向きが異なるだけで、Rowも考え方は同じです。
@Composable
fun ContainerColumn() {
Column(
modifier =Modifier.background(color = Gray),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceAround
// verticalArrangement = Arrangement.SpaceBetween
// verticalArrangement = Arrangement.SpaceEvenly
) {
Text(
text = "あいうえおん",
fontSize = 20.sp,
modifier = Modifier.background(color = Red)
)
Text(
text = "ABCD",
fontSize = 20.sp,
modifier = Modifier.background(color = Blue)
)
Text(
text = "#$",
fontSize = 20.sp,
modifier = Modifier.background(color = Green)
)
}
}
Arrangement.SpaceAround

Arrangement.SpaceBetween

Arrangement.SpaceEvenly

関連記事:



