JetpackComposeのModifierの順序について

3 min read読了の目安(約3200字

先日、JetpackComposeがBetaになりました🎉
#AndroidDevChallengeも開催されてとても盛り上がっていますね!

本記事はJetpackCompose内で重要な役割を担っているModifierの反映順序に関してです。
反映順序を気をつけないと期待した見た目にならずに作業が止まってしまうかもしれません。

※本記事では、1.0.0-beta01時点での内容を扱っています。

Modifierとは

まずはじめに題にあるModifierとはなんなのかに関しての話です。

日本語に訳すと「修飾語句」や「変更・修正する人」といった意味があるみたいです。
JetpackComposeの英語記事を日本語訳かけて読んでいるときに「修飾語」と出てきたら大体Modifierのことを指しています。
自分が翻訳かけながら記事とかを読んでいる感じだと「修飾語」と訳される時が多い印象です。

このModifierがJetpackComposeにおいてどういった役割を果たしているかというと、

  • 背景(色)
  • padding
  • height/width/size
  • クリックイベント
  • 形のクリップ
  • ...

といったレイアウトを調整する上で必要な要素を設定することができるものです。

デフォルトで提供されているComposable関数のほとんどはこのModifierを引数で受け取るように定義されており、いろいろな設定を行うことができます。

使い方の例としては以下のようになります。

Text(
  text = "Text",
  modifier = Modifier
    .padding(20.dp)
    .background(color = Color.Cyan)
)

こうすることによって文字の背景色を設定しつつpaddingの設定もできます。

このコードを見て気づくことがあるかもしれませんが、Modifierの設定はBuilderパターンのコードのように.でどんどん数珠繋ぎ的に書いていくことができます。
前置きが長くなってしまいましたが、こういった書き方をする点が今回の内容になります。

Modifierの順番

先ほど例であげたコードを実行した場合、以下のような見た目になります。(わかりやすくするため上記コードをSurfaceでラップして白背景にしています)

このように背景色をシアンにしつつ、paddingで隙間を開けることができています。

ここで鋭い人は、こういうことが気になるかもしれません。
「paddingとbackgroundを入れ替えるとどうなるんだろう」
いやー鋭い、今回の話はその点に注目しています。

実際に入れ替えてみましょう。

Text(
  text = "Text",
  modifier = Modifier
    .background(color = Color.Cyan)
    .padding(20.dp)
)

背景色の範囲が変わりましたね!
先程までは文字がある範囲だけシアン背景色になっていましたが、今回はpaddingの範囲まで背景色が反映されています。

そうです、書く順番によって結果が変わってきます。

Modifierが反映される順番

左から右へ反映されていきます。
一番最初のコードでいうと

Modifier.padding(20.dp).background(color = Color.Cyan)

というふうに繋げることができます。
これの左から右へなので
まず始めに余白が付き、背景色が設定されるという形です。
こうすることで一番最初の例の見た目になります。

詳しくはCodelabで説明されています

modifiers will update the constraints from left to right,

https://developer.android.com/codelabs/jetpack-compose-layouts#8

どう反映されていっているのか

どう反映されているのか理解するために一つずつ書いていきます。
まず一番初めの例を見ていきます。

Text(
  text = "Text",
  modifier = Modifier
    .padding(20.dp)
    .background(color = Color.Cyan)
)
  • まずは、何も設定していない状態です。
Text(
  text = "Text"
)

  • 次に、paddingのみ設定します。
Text(
  text = "Text",
  modifier = Modifier
    .padding(20.dp)
)

  • 余白がついたら最後に背景色を設定します。
Text(
  text = "Text",
  modifier = Modifier
    .padding(20.dp)
    .background(color = Color.Cyan)
)

なんとなくイメージは掴めたでしょうか?
何も設定されていない状態からpaddingが設定されることでTextの周りに余白がつきます。
そして、Textに背景色がつくことでTextがある範囲のみ背景色がついています。

順番を入れ替えたコードではこれとは逆のことが起こっており、
何も設定されていない状態からTextがある範囲に背景色がつきます。
そして、paddingが設定されることで、色がついている範囲が広がります。

実際に利用されるような複雑な見た目を実装する際に詳細はまた試してみてください。

まとめ

JetpackComposeのModifierでは、繋げる順番によって最終的に出力される結果が変わってきます。
反映される順番としては左から右へになります。

順番によって結果が変わることは、特に要素の順番を気にせず書いていたXMLとは違うため最初は戸惑ったりやりにくいなと感じたりするかもしれません。
ただ、逆に考えると順番が意味をなすことによってXMLの時では実現しにくかった見た目もComposeでは順番の調整次第で実現できるかもしれません。

Betaになってさらに盛り上がってきたJetpackCompose、ぜひ試してみてください!