hiro99ma blog

何か技術的なこと

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

2024/10/15

昨日の記事を読み返し、中央に表示することについて述べていないことに気付く。。。

ともかく、画面の中央に表示したいのであれば下地になるどこかでfillMaxSize()して全部を使えるようにするのが準備として簡単だろう、というのが前回までだ。
そしてようやく中央に表示する話ができる。

私が気になったのは、wrapContentSize()で中央寄せするのは普通なのか、ということ。
Codelabs に書いてあったのでそういうものかと思っていたが、ColumnならverticalArrangementhorizontalAlignmentで同じことができる。

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

プレビュー画像で確認する。
左が今回、右が昨日のwrapContentSize()での場合だ。

image

だいたい同じだが、右の方は下にちょっとスペースが空いている。が、そのくらいだ。

そもそも、wrapContentSize()はコンテンツサイズに関する関数なのになぜ位置についても指定できるのだろうか? Modifierなんだからalign()も使えるだろうし。

wrapContentSize()でいくつか検索した。

レイアウトシステムがスペースの中央に配置しようとする、というのがwrapContentSize()がデフォルトで中央寄せする挙動の元になっているのだろうか。
Columnはデフォルトで左上に配置しようとするからか、どうも中央に配置しようとする姿が思いつかないのだ。

wrapContentSize だけ使う

昨日は wrapContentSize()を使ったが horizontalAlignmentも併用していた。
wrapContentSize()だけだとどうなるか。

@Preview(showBackground = true)
@Composable
fun MyPreview() {
    LemonadeTheme {
        Surface(modifier = Modifier.fillMaxSize()) {
            Column(
                modifier = Modifier.wrapContentSize(),
            ) {
                Text("なるべく長い文字列を表示")
                Image(
                    painter = painterResource(R.drawable.lemon_tree),
                    contentDescription = "lemon tree",
                )
                Button(onClick = {}) {
                    Text("Lemon Tree")
                }
            }
        }
    }
}

Columnの外側だけが中央に寄せられ、中のコンテンツは左に寄っている。

image

horizontalAlignment を指定しない場合

wrapContentSize()を使わず verticalArrangement だけ設定するとどうなるか。

@Preview(showBackground = true)
@Composable
fun MyPreview() {
    LemonadeTheme {
        Surface(modifier = Modifier.fillMaxSize()) {
            Column(
                    verticalArrangement = Arrangement.Center,
            ) {
                Text("なるべく長い文字列を表示")
                Image(
                    painter = painterResource(R.drawable.lemon_tree),
                    contentDescription = "lemon tree",
                )
                Button(onClick = {}) {
                    Text("Lemon Tree")
                }
            }
        }
    }
}

Columnの外側だけが左に寄るのではなく、全部が左に寄ってしまった。
中のコンテンツ位置については wrapContentSize() だけ使った場合と同じだ。

image

Columnの中と外を別々に位置揃えしたいなら、間にもう1つ Column を挟んでコンテンツが水平方向にまとまった部品を作れば良い。
例えばこうすると、全体は左寄せ、中身は中央寄せになる。

@Preview(showBackground = true)
@Composable
fun MyPreview() {
    LemonadeTheme {
        Surface(modifier = Modifier.fillMaxSize()) {
            Column(
                    verticalArrangement = Arrangement.Center,
            ) {
                Column(
                   horizontalAlignment = Alignment.CenterHorizontally,
                ) {
                    Text("なるべく長い文字列を表示")
                    Image(
                        painter = painterResource(R.drawable.lemon_tree),
                        contentDescription = "lemon tree",
                    )
                    Button(onClick = {}) {
                        Text("Lemon Tree")
                    }
                }
            }
        }
    }
}

image

結局どうなのよ

Columnだけでしか見ていないが、こうだった。

今のところ、どっちかじゃないとできないというものはない。
wrapContentSize()だけ設定したのと同じ効果を得ようとしたら Column の外に Column を置いて水平方向だけ制御してもらうことになる、くらいか。

個人的には wrapContentSize() と言われてもピンとこないので、水平方向と垂直方向を操作しそうな verticalArrangementhorizontalAlignment を使うのがいいかと思っている。 が、その意見も実装し続けていたら変わりそうな気がする。

おまけ

呼び出せない Modifier.align() ?

Modifier.align()Imageには使えたがColumnでは使えなさそうだ。
同じModifierを返す関数なのになんでだ?

なるほど、細かいところは読んでいないが直接の型チェック以外にスコープという要素があるのか。

先ほど Image では Modifier.align()が使えたと書いたが、あれはColumnの中にImageがあったので使えたのだった。
なので、先ほど Column では使えなかったと書いた箇所を Columnで囲むと・・・ほら使えた。
なるほどねー。 importするやつが間違っているのかと思って悩んでいたのだ。

こちらはColumnScopeModifier.align()
interfaceなのでコメントしかないが horizontalAlignment 系、つまり横方向しか動かせないことになる。
Columnなので縦の配置をそれぞれが自由に設定されても困るわな。

Surface ?

最初に見たレイアウトのCodelabsSurface を一番下に置くようになっていたのでそう使っていたが、そもそも Surface は何者なのか。
リファレンスページ

Material surface is the central metaphor in material design. (Google翻訳)マテリアルの表面はマテリアル デザインの中心的なメタファーです。

デザインのメタファー、とか言われてもよくわからん。
“surface” もここでは小文字で出てきたので Surface とは違うだろう。
「メタファー(metaphor)=暗喩、隠喩、たとえ」なので、要素、みたいなものだろうか。

そこにあったリンクがマテリアルデザインの “Surfaces” へのリンクだった。
そういうものがあるのね。

わかっていたけど、やはり私はデザインに興味を持っていないようだ。
センスがあるとかなしとかもあるだろうが、そもそもやる気がないのだ。 「私が見づらいのをなんとかしたい」であって「みんなが見やすいようにしたい」ではないのだ。
そういうのは他の人にお任せしたい。

ただ基本を分かっていないとデザインの人とお話しするのにお互い大変そうなので、多少はなんとかしたい気はする。

難しい

これでそろそろレイアウトも簡単なやつならやれるのでは、と思ったがそうもいかなかった。

android: やはりレイアウトは難しい

< Top page