Help us understand the problem. What is going on with this article?

ColumnとRowで理解するJetpack Composeのレイアウト基礎

はじめに

Cloud NextでJetpack Composeは発表され、先日Android Dev Summitでは、大幅なアップデート行われました。

Jetpack Composeのレイアウトを制御するコンポーネントは以下のような階層構造になっています。
下位の階層ほど汎用的なコンポーネントになっています。
上位のコンポーネントは、下位のコンポーネントをラッパーしたものになっており、指定できる機能が限定されています。

jc1.png

これらの階層構造から実際にそれぞれの役割がどのように異なるのかを理解していきたいと思いますが、今回はまずColumnとRowの実際の挙動を確認することで、ColumnとRowの役割を明確にすることでFlexとの違いを理解する第一歩としたいと思います。

Column基本

縦に内部の要素が並びます。

    Column {
        (1..50).toList().map { it.toString() }.forEach { name ->
            Button(name)
        }
    }

Screenshot_1577164971.png

ColumnにLayoutModifierを指定

引数modifilerにはLayoutModifier型を指定して、カラムのサイズなどを指定できます。
指定しない場合は、Modifier.None が指定されます。

modifierにWidthを指定

カラムの幅が40dpになるのでボタンもそれに伴い縮びます。

    Column(modifier = Width(40.dp)){
        (1..50).toList().map { it.toString() }.forEach { name ->
            Button(name)
        }
    }

Screenshot_1577166390.png

modifierにHeightを指定

カラムの高さが400dpになるので、一部のボタンが表示されません。

    Column(modifier = Height(400.dp)){
        (1..50).toList().map { it.toString() }.forEach { name ->
            Button(name)
        }
    }

Screenshot_1577166678.png

WidthとHeightを指定する場合は、Sizeを利用します。

    Column(modifier = Size(width = 400.dp, height = 100.dp)){
        (1..50).toList().map { it.toString() }.forEach { name ->
            Button(name)
        }
    }

modifierにExpandedを指定

利用できるスペースをすべて使うように拡大されます。
わかりやすいように背景のカラーを設定します。

  • None
    Surface(color = Color.Gray) {
        Column(modifier = Modifier.None) { // 指定しない場合はNoneになる
            Surface(color = Color.Black) {
                Column(modifier = Width(100.dp)) {
                    (1..50).toList().map { it.toString() }.forEach { name ->
                        Button(name)
                    }
                }
            }
        }
    }

Screenshot_1577693774.png

  • Expanded
    Surface(color = Color.Gray) {
        Column(modifier = Expanded) {
            Surface(color = Color.Black) {
                Column(modifier = Width(100.dp)) {
                    (1..50).toList().map { it.toString() }.forEach { name ->
                        Button(name)
                    }
                }
            }
        }
    }

Screenshot_1577693870.png

他にはExpandedHeight、ExpandedWidthも存在します。

wrapを用いて複数のmodifierの指定

最初に書いた方が優先されるので、以下の例ではSizeで指定した高さ10px、はHeightで指定した高さ100.dpに上書きされます。

    Column(modifier = Height(100.dp) wraps Size(width = 100.dp , height = 10.dp)){
        (1..50).toList().map { it.toString() }.forEach { name ->
            Button(name)
        }
    }

Screenshot_1577169640.png

他にもModifierが用意されていそうですが、すべてを一覧で確認するドキュメントが見つからなかったためわかりませんでした。

ColumnにArrangementを指定

arrangementは配置を意味します。
デフォルトでは Arrangement.Begin が指定されています。

以降の例では、Column自体が内部のコンテンツのサイズに縮まってしまうと表示結果に違いがでないため、modifilerにExpandedを指定して説明します。

arrangementにArrangement.Endを指定

終端に並びます。

    Column(
        modifier = Expanded,
        arrangement = Arrangement.End
    ){
        (1..3).toList().map { it.toString() }.forEach { name ->
            Button(name)
        }
    }

Screenshot_1577167692.png

arrangementにArrangement.Centerを指定

中央に並びます。

    Column(
        modifier = Expanded,
        arrangement = Arrangement.Center
    ){
        (1..3).toList().map { it.toString() }.forEach { name ->
            Button(name)
        }
    }

Screenshot_1577167842.png

arrangementにArrangement.SpaceAroundを指定

子要素間に等間隔に並べます。開始地点と子要素、子要素と終了地点の間は子要素間のスペースの半分になります。

    Column(
        modifier = Expanded,
        arrangement = Arrangement.SpaceAround
    ){
        (1..3).toList().map { it.toString() }.forEach { name ->
            Button(name)
        }
    }

Screenshot_1577167896.png

arrangementにArrangement.SpaceBetweenを指定

子要素間が等間隔に並びます。開始地点、終了地点のスペースはありません。

    Column(
        modifier = Expanded,
        arrangement = Arrangement.SpaceBetween
    ){
        (1..3).toList().map { it.toString() }.forEach { name ->
            Button(name)
        }
    }

Screenshot_1577167953.png

arrangementにArrangement.SpaceEvenlyを指定

開始地点、子要素間、終了地点が等間隔に並びます。

    Column(
        modifier = Expanded,
        arrangement = Arrangement.SpaceEvenly
    ){
        (1..3).toList().map { it.toString() }.forEach { name ->
            Button(name)
        }
    }

Screenshot_1577167992.png

Rowとの違い

RowについてもColumnが縦に子要素を並べるのに対して、横に並べるだけで挙動は同じです。

Screenshot_1577165219.png

Flexとの違い

FlexにはColumnに存在しないMainAxisAlignmentとCrossAxisAlignmentが存在します。

MainAxisAlignmentは内部的にはArrangementを持っており、また FlexはFlexLayoutの arrangement = mainAxisAlignment.arrangement を渡していることからも同じ役割であることがわかります。

CrossAxisAlignmentは、新規に追加されている値で、おそらくColumnの場合は横方向、Rowの場合は縦方向にレイアウトの制御を行うものだと考えられます。

まとめ

Columnを例にLayoutModifierとArrangementについて説明しました。
Column, RowとFlexの違いはCrossAxisAlignmentにあることがわかりました。

次回はFlex、FlexColumn、FlexRowを調査します。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした