Jetpack Composeでコンポーネントを丸く切り抜きたい


Modifierを使って、画像などのコンポーネントを丸く切り抜く方法を紹介します。背景色を設定しつつ切り抜きも行う方法も紹介します。

やりたいこと

画像を丸く切り抜く

背景色の設定と切り抜きを合わせて行う

1つ目の例は、画像を単純に丸く切り抜いて表示しています。

2つ目の例は、透過画像の背景に緑色を指定しつつ、丸く切り抜いて表示しています。

環境

以下の環境で確認しています。

  • Kotlin 1.6.10
  • Jetpack Compose 1.1.1

単純な切り抜き

Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.background(Color.Black)
.size(100.dp),
) {
Image(
painter = painterResource(R.drawable.hitsuji),
contentDescription = null,
modifier = Modifier
.size(64.dp)
.clip(CircleShape)
)
}

単純に切り抜きたい場合は、Modifier.clip()を使います。引数のshapeにはCircleShapeを指定します。ちなみにCircleShapeのほかには、RoundedCornerShapeCutCornerShapeなどを指定できます。

背景色を設定して切り抜き

Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.background(Color.Black)
.size(100.dp),
) {
Image(
painter = painterResource(R.drawable.ic_launcher_foreground),
contentDescription = null,
modifier = Modifier
.size(64.dp)
.background(
color = Color.Green,
shape = CircleShape,
)
)
}

背景色を設定しつつ切り抜きたい場合はModifier.background()を使います。color引数に色を指定し、shape引数にCircleShapeを指定します。この例では背景が透明な画像のコンポーネントに、緑色の背景を設定し、なおかつ丸く切り抜いて表示しています。

なお、Modifier.background()colorだけを指定し、Modifier.clip()と組み合わせて使うという実装も考えられますが、これは順序によって結果が異なり、不具合のもとになるので避けた方が無難です。

Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.background(Color.Black)
.size(100.dp),
) {
Image(
painter = painterResource(R.drawable.ic_launcher_foreground),
contentDescription = null,
modifier = Modifier
.size(64.dp)
.clip(CircleShape)
.background(Color.Green)
)
}

このようにclip()background()の順に書くと意図したとおりに切り抜かれますが・・・

Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.background(Color.Black)
.size(100.dp),
) {
Image(
painter = painterResource(R.drawable.ic_launcher_foreground),
contentDescription = null,
modifier = Modifier
.size(64.dp)
.background(Color.Green)
.clip(CircleShape)
)
}

background()clip()の順に書くと切り抜かれません。

おそらく、background()shape引数のデフォルト値がRectangleShapeなので、clip()に指定したCircleShapeと競合しているのだと思いますが、詳しい内部動作までは確認できていません。