hiro99ma blog

何か技術的なこと

android: Composableのレイアウト (1)

2024/10/04

Android Codelabs の Compose UIに関する最初のコースをやっている。
そして、やってみましょう的なところで詰まってしまった。

4. Compose 象限というページで、同じ構成のカードを文言だけ変更して4枚並べるというだけ。
ただそれだけだというのに。。。

ヒントとして Weight modifier を使うことが書かれているので、どういう動作をするか簡単に見ておく。

このコースの途中にあった HappyBirthday サンプルにプレビューだけ突っ込んだ。
テーマ名がHappyBirthdayThemeなところ以外は他でも使えるだろう。

@Preview(
    name = "sample",
    showBackground = true,
)
@Composable
fun SamplePreview() {
    @Composable
    fun innerCard(modifier: Modifier = Modifier) {
        Column(modifier = modifier) {
            Text(text = "Happy Birthday Tom!")
            Text(text = "from Jerry")
        }
    }
    HappyBirthdayTheme {
        Surface(
            modifier = Modifier.fillMaxSize(),
            color = Color.Red,
        ) {
            Column {
                innerCard(
                    modifier = Modifier
                        .background(Color.Blue)
                        .weight(0.5F)
                )
                Row {
                    innerCard(
                        modifier = Modifier
                            .background(Color.Green)
                            .weight(0.5F)
                    )
                }
            }
        }
    }
}

構成はこんな感じ。
HappyBirthday をベースにしていたので modifier などがちょっと違うが、今回見てみる内容と関係なさそうだったので気にしなくてよかろう。

image

図の AAA が↑の innerCard に当たる。
ColumnTextが2つ並んでいるだけである。

それをさらにColumnで2つ並べている。
画面全体が見えないと分かりづらいのでSurfacefillMaxSize()している。 背景色は赤。

modifierとくになし

レイアウトに関する設定を特に行わないと、Textはそれぞれ最初の領域を確保して左上に寄るようにレンダリングされた。

image

両方にfillMaxSize()をつける

innerCard()modifierfillMaxSize()を付けて呼び出すと Columnmodifierとして与えられる。
単に指定するだけだと、最初にレンダリングする部品が全部奪ってしまうようだ。

image

下だけfillMaxSize()を付ける

先ほどは両方付けて先にレンダリングされる方?だけしか見えなかったので、今度は下の方にだけ付けてみた。
そうすると、先に上をレンダリングしたあとに下を最大にレンダリングしたのかこうなった。

image

両方にweightを付ける

では両方に同じ重さのweightを付けてみる。
横方向はそのままで縦の方向にweightで指定した比率のレンダリングが行われた。

image

0.5FFはC言語などと同じく単精度浮動小数点(Float)定数ということだろう。 1だと整数だからダメだし、1.0だと倍精度(Double)になるからそれはそれでダメなのだ。

上だけweightを付ける

先ほどのfillMaxSize()は片方だけ設定するとレンダリングされる順番のような感じだった。
weightはどうなのかと上にだけ付けたが、こちらは下の方も描画された。

image

なんとなく、誰かがweightを付けるとそれ以外の付けていない部品は最小限の大きさになるように見える。
間にもう1つ部品を入れて上2つにweightを設定したが、一番下もレンダリングされた。

image

weightが連続しない

weight設定した部品に設定していない部品が挟まるとどうなるか。
特に関係なく、weightでの比率になりつつもweight無しについてもレンダリングされる。

image

fillMaxWidth()

Columnで横に広げたい場合はfillMaxWidth()か。

image

ColumnとRowが混ざる

Columnの中にColumnを2つ入れていたが、その片方がRowになったらどうなるのか。

まず、Rowに入れ込むだけだと特に変わりない。

image

両方にweightを設定。
innerCard()の引数なので、Rowに入れ込んだ方も最終的にはColumnmodifierweightを設定していることになる。

image

これはどう解釈すると良いのか。
まず、weightは直接設定したColumnに対してではないというか、そのColumnそのものに影響するわけではないことになる。

ありそうなのは、部品を配置しようとする上側の部品が配下の部品が持つweightを見ている、という考え方だ。
先ほどは一番上のColumnがその中に持つColumnたちのweightを見てサイズを決めていたのだ。
今回はRowがその中のColumnが持つweightを見て、他に部品がないので横方向に目一杯引き延ばした、というわけだ。
そしてその上のColumnは配下にRowColumnを持っていて、weightを設定していないRowは最低限の大きさ、設定してあるColumnは残りの領域を縦方向に目一杯引き延ばした、とすればつじつまがあう。

逆に下をRowで囲むと、やはりそういうレンダリングになった。

image

おわりに

あってるかどうかわからんが、自分なりに解釈してみた。

しかしこれ、数個しかないからなんとかなるものの難しいな。
テストアプリくらいだったら何とかなる!と思いたい。

< Top page