hiro99ma blog

何か技術的なこと

android: 中央に表示する (1)

2024/10/14

Android で画面レイアウトを作っていると、コンテンツを中央に寄せるというか揃えるというかしたいことがある。

Android Codelabs ではここで出てきた(他でも出ているが)。

3. レイアウト インフラストラクチャを作成する

実際に揃ったので何も考えていなかったが、よく考えるとModifier.align()というのもあるしColumnにはverticalArrangementhorizontalAlignmentもある。
どうするのがよいのだろう?

Codelabsでの設定

この Codelabs ではどうなっているか。

なのでModifier.fillMaxSize().wrapContentSize(Alignment.Center)Columnが設定することになる。

コンテンツをそれぞれ上に積むような図にするとこうなるか。

image

fillMaxSize() しないといけないのか

fillMaxSize()SurfaceColumnに出てくるが、これは毎回いるのだろうか?
試してみよう。

両方付ける

Codelabs の例に似たような構造を作る。

@Preview(showBackground = true)
@Composable
fun MyPreview() {
    LemonadeTheme {
        Surface(modifier = Modifier.fillMaxSize()) {
            Column(
                modifier = Modifier.fillMaxSize().wrapContentSize(Alignment.Center),
                horizontalAlignment = Alignment.CenterHorizontally,
            ) {
                Image(
                    painter = painterResource(R.drawable.lemon_tree),
                    contentDescription = "lemon tree"
                )
                Button(onClick = {}) {
                    Text("Lemon Tree")
                }
            }
        }
    }
}

Android Studio の Previewで確認する。

image

Surface にだけ付ける

Surface にだけ fillMaxSize()を付け、Columnからは外してwrapContentSize()だけにする。

@Preview(showBackground = true)
@Composable
fun MyPreview() {
    LemonadeTheme {
        Surface(modifier = Modifier.fillMaxSize()) {
            Column(
                modifier = Modifier.wrapContentSize(Alignment.Center),
                horizontalAlignment = Alignment.CenterHorizontally,
            ) {
                Image(
                    painter = painterResource(R.drawable.lemon_tree),
                    contentDescription = "lemon tree"
                )
                Button(onClick = {}) {
                    Text("Lemon Tree")
                }
            }
        }
    }
}

両方付けたときと違いはないように見える。

image

Column にだけ付ける

今度は逆に Columnにだけ付ける。

@Preview(showBackground = true)
@Composable
fun MyPreview() {
    LemonadeTheme {
        Surface(modifier = Modifier) {
            Column(
                modifier = Modifier.fillMaxSize().wrapContentSize(Alignment.Center),
                horizontalAlignment = Alignment.CenterHorizontally,
            ) {
                Image(
                    painter = painterResource(R.drawable.lemon_tree),
                    contentDescription = "lemon tree"
                )
                Button(onClick = {}) {
                    Text("Lemon Tree")
                }
            }
        }
    }
}

こちらも違いはないように見える。

image

全部外す

SurfaceからもColumnからも外すと、プレビューで表示するサイズが分からないためコンテンツだけになる。

@Preview(showBackground = true)
@Composable
fun MyPreview() {
    LemonadeTheme {
        Surface(modifier = Modifier) {
            Column(
                modifier = Modifier.wrapContentSize(Alignment.Center),
                horizontalAlignment = Alignment.CenterHorizontally,
            ) {
                Image(
                    painter = painterResource(R.drawable.lemon_tree),
                    contentDescription = "lemon tree"
                )
                Button(onClick = {}) {
                    Text("Lemon Tree")
                }
            }
        }
    }
}

おそらく実機で表示すると左上に現れるのだろう。

image

どうすればいいんだ!

fillMaxSizeの説明がよくわからないのだ。
実際にやっている計算を書いているのだろうけど、結果としてどうなるのかがわからない。
制約と修飾子の順序の「レイアウトフェーズの制約」辺りを理解しないと API名だけで判断していたら痛い目を見そうだ。

制約の理解は課題として残しておこう。

上の例だと関数無しにしたのでわかりづらいが、ある程度のまとまりで関数化していって、上の方はそれを呼び出して配置するのに専念するのだろう。
今回だと、Column以下が 1つの関数になっていて上側はそれをどこに配置したいかでModifierだけ指定するような感じだろうか。

見た目では同じように見えるけど、実装していって仕様変更すると苦しみそうな分野だ。

< Top page