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 などがちょっと違うが、今回見てみる内容と関係なさそうだったので気にしなくてよかろう。

図の AAA が↑の innerCard に当たる。
ColumnでTextが2つ並んでいるだけである。
それをさらにColumnで2つ並べている。
画面全体が見えないと分かりづらいのでSurfaceでfillMaxSize()している。
背景色は赤。
modifierとくになし
レイアウトに関する設定を特に行わないと、Textはそれぞれ最初の領域を確保して左上に寄るようにレンダリングされた。

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

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

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

0.5FのFはC言語などと同じく単精度浮動小数点(Float)定数ということだろう。
1だと整数だからダメだし、1.0だと倍精度(Double)になるからそれはそれでダメなのだ。
上だけweightを付ける
先ほどのfillMaxSize()は片方だけ設定するとレンダリングされる順番のような感じだった。
weightはどうなのかと上にだけ付けたが、こちらは下の方も描画された。

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

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

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

ColumnとRowが混ざる
Columnの中にColumnを2つ入れていたが、その片方がRowになったらどうなるのか。
まず、Rowに入れ込むだけだと特に変わりない。

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

これはどう解釈すると良いのか。
まず、weightは直接設定したColumnに対してではないというか、そのColumnそのものに影響するわけではないことになる。
ありそうなのは、部品を配置しようとする上側の部品が配下の部品が持つweightを見ている、という考え方だ。
先ほどは一番上のColumnがその中に持つColumnたちのweightを見てサイズを決めていたのだ。
今回はRowがその中のColumnが持つweightを見て、他に部品がないので横方向に目一杯引き延ばした、というわけだ。
そしてその上のColumnは配下にRowとColumnを持っていて、weightを設定していないRowは最低限の大きさ、設定してあるColumnは残りの領域を縦方向に目一杯引き延ばした、とすればつじつまがあう。
逆に下をRowで囲むと、やはりそういうレンダリングになった。

おわりに
あってるかどうかわからんが、自分なりに解釈してみた。
しかしこれ、数個しかないからなんとかなるものの難しいな。
テストアプリくらいだったら何とかなる!と思いたい。