LoginSignup
36
22

More than 1 year has passed since last update.

【Jetpack Compose】ColumnとRowで知っていると便利なこと3選

Last updated at Posted at 2021-11-30

はじめに

本記事は with Advent Calendar 2021 1日目の記事です。

こんにちは with でAndroid エンジニアをしている石田です。withでは Jetpack Compose を段階的にプロダクトに導入しています。

本記事では、Compose の基本レイアウトである ColumnとRow で個人的によく使う 便利だなと感じたユースケースを3つ 紹介します。

Weightを設定しつつ可能ならば詰めてレイアウトする

fig1.png

Column/Row のスコープでは Modifier.weight で Weight を指定することができ、指定した値の比率で子の高さもしくは幅が決定されます。通常は内容に関係なくその比率の分だけ領域が確保されるますが、可能ならば詰めてレイアウトしたい場合はどうすればいいでしょうか。

実は Modifier.weight()第2引数に fill: Boolean 取ることができてfill=false を指定することで必要なだけ高さもしくは幅を取るという挙動にすることができます。これは ConstraintLayout で言うところの app:layout_constraintHeight_default="wrap" に相当します。

サンプルコード

以下の要件を満たすサンプルを示します。

  1. 名前の幅は伸縮し、年齢は名前の横に詰めてレイアウトする
  2. 名前が長い場合は末尾を省略する
  3. 年齢は常に省略されない
@Composable
fun WeightFillFalseExample() {
    Column {
        UserItem("なおと", 26)
        UserItem("なおと@Qiita Advent Calendar 2021参加中", 26)
    }
}

@Composable
private fun UserItem(
    name: String,
    age: Int,
) {
    Row(
        verticalAlignment = Alignment.CenterVertically,
        modifier = Modifier.padding(16.dp)
    ) {
        Text(
            text = name,
            modifier = Modifier.weight(weight = 1f, fill = false), // < -- ココ!
            style = MaterialTheme.typography.bodyMedium,
            maxLines = 1,
            overflow = TextOverflow.Ellipsis,
        )
        Spacer(modifier = Modifier.width(16.dp))
        Text(
            text = "${age}歳",
            style = MaterialTheme.typography.bodySmall,
        )
    }
}

子の間に均等にスペースを空けたい

fig2.png

ColumnやRowで子をスペースを空けながら等間隔に並べたい場合は Arrangement.spacedBy を使うと便利です。これは ConstraintLayout の Flow で言うところのapp:flow_horizontalGap / app:flow_verticalGap に相当します。 Modifier.paddingSpacer を使う方法に比べて コンポーザブルのツリー構造をシンプルに保つことができ、コードの見通しも良くなると思います。

サンプルコード

サンプルを示します。 LazyRowに対して Arrangement.spacedBy を使ってますが、 Row でも同様です。Columnの場合は horizontalArrangement の部分が verticalArrangement になります。

@Composable
fun ArrangementSpacedbyExample() {
    LazyRow(
        contentPadding = PaddingValues(all = 16.dp),
        horizontalArrangement = Arrangement.spacedBy(16.dp),     // < -- ココ!
    ) {
        item { Tag(text = "焼き肉🍖") }
        item { Tag(text = "お寿司🍣") }
        item { Tag(text = "ピザ🍕") }
        item { Tag(text = "お弁当🍱") }
    }
}

@Composable
private fun Tag(text: String) {
    Box(
        modifier = Modifier
            .clip(RoundedCornerShape(100))
            .background(MaterialTheme.colorScheme.secondaryContainer)
            .padding(horizontal = 12.dp, vertical = 4.dp),
    ) {
        Text(
            text = text,
            style = MaterialTheme.typography.bodySmall,
            color = MaterialTheme.colorScheme.onSecondaryContainer,
        )
    }
}

子を右から左に配置したい

fig3.png

Rowは通常 子を左から右に配置していきますが、右から左に配置することも可能です。配置の方向を変えるには LocalLayoutDirection の値を設定します。

サンプルコード

サンプルを示します。 LocalLayoutDirection の値は CompositionLocalProvider を使って指定します。

@Composable
fun LayoutDirectionExample() {
    Column {
        ProvideLayoutDirection(layoutDirection = LayoutDirection.Ltr) {
            Seasons()
        }

        ProvideLayoutDirection(layoutDirection = LayoutDirection.Rtl) {
            Seasons()
        }
    }
}

@Composable
private fun ProvideLayoutDirection(
    layoutDirection: LayoutDirection,
    content: @Composable () -> Unit,
) {
    CompositionLocalProvider(
        LocalLayoutDirection provides layoutDirection, // < -- ココ!
        content = content,
    )
}

@Composable
private fun Seasons() {
    Row(
        modifier = Modifier.padding(16.dp),
        horizontalArrangement = Arrangement.spacedBy(16.dp),
    ) {
        Text(text = "春")
        Text(text = "夏")
        Text(text = "秋")
        Text(text = "冬")
    }
}

まとめ

ColumnとRow で個人的によく使う便利だなと感じたユースケースを3つ紹介しました。

動作可能なサンプルコードをGitHubで公開している のでこちらも併せてご参照ください。

36
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
22