こんにちは。エキサイト株式会社 Androidエンジニアの克です。
今回は、ContentColorを使って色の変更をシンプルにするお話をします。
まずは普通に要素を表示してみる
とりあえず適当なアイコンとテキストを表示するコードを用意しました。
Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center, ) { Column { Row( modifier = Modifier.padding(8.dp), verticalAlignment = Alignment.CenterVertically, ) { Icon( imageVector = Icons.Rounded.Android, contentDescription = null, ) Text(text = "サンプル1") } Row( modifier = Modifier.padding(8.dp), verticalAlignment = Alignment.CenterVertically, ) { Icon( imageVector = Icons.Rounded.Android, contentDescription = null, ) Text(text = "サンプル2") } } }
こちらを実行すると次のような画面になります。
もしこの状態で「上側の要素の背景を黒くしたい」という要件が出てきたらどのようにするでしょうか。
単純にRow
の背景を黒くしてみます。
---
Row(
modifier = Modifier
.background(Color.Black)
.padding(8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
---
アイコンとテキストは黒のままなので、当然ですが見えなくなってしまいます。
そのためアイコンとテキストの色も変えていきます。
--- Icon( imageVector = Icons.Rounded.Android, contentDescription = null, tint = Color.White, ) Text( text = "サンプル1", color = Color.White, ) ---
これで要件を満たすことはできましたが、このやり方には下記のような問題点があります。
- 要素が増えた場合、全ての要素に色の設定をする必要がある
- 設定の漏れにより、意図しない表示になりやすい
ContentColorを使うようにすると、こういった問題を解決することができます。
ContentColorとは
既存で用意されているComposableの多くは、デフォルトでContentColorを参照するものが多いです。
@Composable fun Icon( --- tint: Color = LocalContentColor.current.copy(alpha = LocalContentAlpha.current) )
@Composable fun Text( --- ) { val textColor = color.takeOrElse { style.color.takeOrElse { LocalContentColor.current.copy(alpha = LocalContentAlpha.current) } }
例であげたものでは LocalContentColor.current
が使われています。
こちらは現在設定されているContentColorを参照するというもので、このContentColorを変更してあげれば自動的に要素に反映されるということになります。
ContentColorを使ってみる
先程のコードを、ContentColorを使用したものに変更してみましょう。
鍵となるのはSurface
です。
Surface
はBox
などと同様に要素を配置できるものですが、名前の通り要素の下に敷くような用途で使用します。
Surface
では自身の色とともに、ContentColorを設定することもできるので今回はこちらを活用していきます。
公式のドキュメントでも、背景色の設定にはSurfaceを使用することが記載されています。
要素の背景色を設定する際は、Surface を使用することをおすすめします。Surface は適切なコンテンツ色を設定します。Modifier.background() で直接呼び出すと適切なコンテンツ色が設定されないため、ご注意ください。
先程のコードをSurface
に置き換えたものが下記となります。
Surface( color = Color.Black, contentColor = Color.White, ) { Row( modifier = Modifier.padding(8.dp), verticalAlignment = Alignment.CenterVertically, ) { Icon( imageVector = Icons.Rounded.Android, contentDescription = null, ) Text(text = "サンプル1") } }
要素自体に色を指定する必要がなくなったので、どれだけ要素が増えようとも困ることはありませんね。
最後に
個別の対応や同じコードの繰り返しを多用すると、仕様の変更に対応しにくくなったり人為的なミスが発生しやすくなります。 フレームワークが用意してくれている共通化できるような機能を積極的に活用していくようにしましょう。