Jetpack composeは、アプリ開発に必要な一通りのUIコンポーネントをライブラリで提供しています。
そのライブラリ中のSpacerについて、構成や使用方法などをまとめます。
※環境:Android Studio Hedgehog | 2023.1.1 Patch 2
Kotlin 1.9.0
Compose Compiler 1.5.1
androidx.compose.foundation 1.5.0
UIの概要
Spacerは空きスペースを確保するUI要素です。
@Preview_mdpi
@Composable
fun ColumnSpacerSample() {
Column(modifier = Modifier.size(320.dp, 240.dp)) {
Image(
painter = painterResource(R.drawable.leaf1),
contentDescription = null,
modifier = Modifier.height(100.dp),
contentScale = ContentScale.None
)
Spacer(modifier = Modifier.height(30.dp))
Image(
painter = painterResource(R.drawable.leaf2),
contentDescription = null,
modifier = Modifier.height(100.dp),
contentScale = ContentScale.None
)
}
}

関数の引数
Spacerの状態(装飾、演出など)は、引数により指定できます。
表示するコンテンツ(図形や文字など)を持たないので、与えるべき状態はmodifierのみです。
@Composable
@NonRestartableComposable
fun Spacer(modifier: Modifier) { ... }
| 引数 | 概要 | |
|---|---|---|
| modifier | Modifier | UI全般のCompose修飾子 |
関数の構成
関数は内部にLayout関数(Composable関数)のみを持ちます。
Layoutは「自身のサイズを決定する機能」をシステムへ登録する関数です。この機能はSpacerMeasurePolicyで定義されており、描画処理のLayoutフェーズで実行されます。
※描画処理については「Jetpack Compose:Composeによるアプリ画面の描画」を参照
@Composable
@NonRestartableComposable
fun Spacer(modifier: Modifier) {
Layout({}, measurePolicy = SpacerMeasurePolicy, modifier = modifier)
}
private object SpacerMeasurePolicy : MeasurePolicy {
override fun MeasureScope.measure(
measurables: List<Measurable>,
constraints: Constraints
): MeasureResult {
return with(constraints) {
val width = if (hasFixedWidth) maxWidth else 0 // widthの算出
val height = if (hasFixedHeight) maxHeight else 0 // heightの算出
layout(width, height) {} // サイズを通知
}
}
}
Spacerのサイズ(widthまたはheight)は、制約Constraints(許されるサイズの範囲)が固定化された時(hasFixedXXX==true)に決まります。
固定化されなければ、サイズは0になり、空きスペースは確保されません。
固定化する条件は次のCompose修飾子を実行したときになります。
- Modifier#size
- Modifier#width / #height
- Modifier#fillMaxWidth / #fillMaxHeight
応用例1:Divider
backgroundの配色されたSpacerを、Divider(仕切り)として用いた例です。
@Preview_mdpi
@Composable
fun ColumnSpacerSample() {
Column(modifier = Modifier.size(320.dp, 240.dp)) {
Image(
painter = painterResource(R.drawable.leaf1),
...
)
Spacer(
modifier = Modifier
.height(2.dp)
.fillMaxWidth()
.background(Color.LightGray)
)
Image(
painter = painterResource(R.drawable.leaf2),
...
)
}
}

@Preview_mdpi
@Composable
fun RowSpacerSample() {
Row(modifier = Modifier.size(320.dp, 240.dp)) {
Image(
painter = painterResource(R.drawable.leaf1),
...
)
Spacer(
modifier = Modifier
.fillMaxHeight()
.width(2.dp)
.background(Color.LightGray)
)
Image(
painter = painterResource(R.drawable.leaf2),
...
)
}
}

※既にマテリアルデザインの指標に準拠したDividerがライブラリで提供されています。詳細は「Compose UI:Divider」を参照。
応用例2:Canvas
Jetpack Composeのライブラリで提供されるCanvas(Composable関数)は、Spacerを応用したUI要素です。
CanvasはSpacerによって確保された空きスペースへ、Modifier#drawBehindを使って図形の描画を可能にしています。
@Composable
fun Canvas(modifier: Modifier, onDraw: DrawScope.() -> Unit) =
Spacer(modifier.drawBehind(onDraw))
CanvasはSpacerと同様に、制約Constraintsが固定化(例は120×120)されている必要があります。
@Preview_mdpi
@Composable
fun CanvasSample() {
Box(modifier = Modifier.size(320.dp, 240.dp)) {
Canvas(
modifier = Modifier
.size(120.dp) // 120x120へ固定化
.background(Color.LightGray)
) {
drawRect( // 矩形:DrawScopeに定義された描画関数
Color.Blue,
topLeft = Offset(10.dp.toPx(), 10.dp.toPx()),
size = Size(100.dp.toPx(), 100.dp.toPx())
)
drawCircle( // 円:DrawScopeに定義された描画関数
Color.Red,
radius = 50.dp.toPx()
)
}
}
}

関連記事:
