Android / Kotlin / Programming

Jetpack Composeで影(Shadow)を付ける方法と課題

Jetpack Composeでコンポーネントに影を付ける方法とその中で発見した問題点をメモしてます
一番簡単なMaterial Design3のCardコンポーネントを使用する方法とModifierで設定する方法を取り扱っています
Cardを使用する方がおすすめです

影のつけ方 – Cardコンポーネント

Cardには、Filled Card(塗りつぶしありカード)とOutlined Card(塗りつぶしなしカード)の2種類あります
以下では両方のUI紹介とパラメーターについてまとめています

Filled Card(塗りつぶしありカード)のUI

Card(
    colors = CardDefaults.cardColors(
        containerColor = MaterialTheme.colorScheme.surfaceVariant,
    ),
    modifier = Modifier
        .size(width = 240.dp, height = 100.dp)
) {
    Text(
        text = "Filled",
        modifier = Modifier
            .padding(16.dp),
        textAlign = TextAlign.Center,
    )
}

Outlined Card(塗りつぶしなしカード)のUI

OutlinedCard(
    colors = CardDefaults.cardColors(
        containerColor = MaterialTheme.colorScheme.surface,
    ),
    border = BorderStroke(1.dp, Color.Black),
    modifier = Modifier
        .size(width = 240.dp, height = 100.dp)
) {
    Text(
        text = "Outlined",
        modifier = Modifier
            .padding(16.dp),
        textAlign = TextAlign.Center,
    )
}

パラメーターについて

パラメーター説明
elevationカードの高さ(影の濃さ)の変更
colors 塗りつぶしの色の変更
enabledCardコンポーネントの使用可否の変更
(falseの場合はfalse用の色に自動的に変更される)
onClickクリックされたときの動作の変更

例えば影の色を変更したい場合は、elevationに適切な値を渡すことで好みのUIに変更できます

影のつけ方

  val elevation = 4.dp
  
  Box(
      modifier = modifier
          .wrapContentHeight()
          .shadow(
              elevation = elevation,
          ),
  ) {
      // Boxの中身
  }

Modifier.shadow()で影を付けることができ、各引数で詳細を設定できます
設定必須の引数はelevationのみで、影の濃さ(Z方向での高さ)をpxで表しています

ちなみに下記はコンポーネントを丸角にして影を付与するコードです
shadow()のshape引数に設定することでコンポーネントの形を変更することができます

  val elevation = 4.dp
  val cornerRadius = 8.dp
  
  Box(
      modifier = modifier
          .wrapContentHeight()
          .shadow(
              elevation = elevation,
              shape = RoundedCornerShape(
                  size = cornerRadius
              ),
          ),
  ) {
      // Boxの中身
  }

課題

上記2枚のキャプチャの両方で確認できますが、青枠と上下の影に注目すると、下の影だけグラデーションの部分が高さとして計算されていないように思えます
これを解決するには根本的に変更し、Material Design3のカードを使用するのが一番おすすめです
一応、使用しない場合の回避策(暫定対処)を下記に残しておきます

解決方法

  val elevation = 4.dp
  val cornerRadius = 8.dp
  val offsetY = elevation / 2

  Box(
      modifier = modifier
          .wrapContentHeight()
          .shadow(
              elevation = elevation,
              shape = RoundedCornerShape(
                  size = cornerRadius
              ),
          )
          .offset(
              y = offsetY
          ),
  ) {
      content()
  }

offsetを使用し、Boxの位置をY方向に移動させています
褒められる解決方法では全くありませんが、暫定的にはこれでしのげると思います

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です