Jetpack compose 1.9.0 でネオンサイン風の枠線を遊びで作った
Jetpack compose 1.9.0
Jetpack compose BoM 2025.08.00 (1.9.0) がリリースされました 🎉
- Shadows
- New Visibility modifiers
- Rich styling in OutputTransformation
- LazyLayout
- New annotations and Lint checks
など様々な更新がありましたが、今回 Shadows の追加でできるようになったネオンサイン風の枠線を遊びで作りました。
今回の成果物
Shadows
今回のアップデートで Modifier
に dropShadow と innerShadow が簡単に設定できるようになりました。
dropShadow
公式ブログに書かれている DropShadow
というクラスは見つからなかったので API reference を参照して Shadow を使用しています。
修飾子の順序の重要性 にも記載の通り順番が重要で、background
よりも前に記述する必要があります。
@Preview(showBackground = true)
@Composable
private fun DropShadowPreview() {
val shape = RoundedCornerShape(size = 20.dp)
Box(contentAlignment = Alignment.Center) {
Box(
modifier = Modifier
.padding(all = 20.dp)
.size(size = 200.dp)
.dropShadow(
shape = shape,
shadow = Shadow(
radius = 12.dp,
color = Color(0xFF0088ff),
),
)
.background(
color = Color(0xFF0088ff),
shape = shape,
),
)
}
}
dropShadow
innerShadow
こちらも同じく公式ブログに書かれている InnerShadow
というクラスは見つからなかったので API reference を参照して Shadow を使用しています。
background
よりも後に記述する必要があります。
@Preview(showBackground = true)
@Composable
private fun InnerShadowPreview() {
val shape = RoundedCornerShape(size = 20.dp)
Box(contentAlignment = Alignment.Center) {
Box(
modifier = Modifier
.padding(all = 20.dp)
.size(size = 200.dp)
.background(
color = Color(0xFF0088ff),
shape = shape,
)
.innerShadow(
shape = shape,
shadow = Shadow(
radius = 12.dp,
color = Color.Black,
),
)
)
}
}
innerShadow
ネオンサイン風の枠線
dropShadow
と innerShadow
を合わせると CSS で見かけるネオンサインのような枠線ができました。
spread
を使用するとさらにそれっぽく見えます。
@Preview(showBackground = true, backgroundColor = 0xFF000000)
@Composable
private fun NeonPreview() {
val neonColor = Color(0xFF0088ff)
val shape = RoundedCornerShape(size = 20.dp)
Box(contentAlignment = Alignment.Center) {
Box(
modifier = Modifier
.padding(20.dp)
.size(200.dp, 100.dp)
.dropShadow(
shape = shape,
shadow = Shadow(
radius = 12.dp,
color = neonColor,
spread = 3.dp,
),
)
.background(
color = Color.Black,
shape = shape,
)
.border(
width = 2.dp,
color = Color.White,
shape = shape,
)
.innerShadow(
shape = shape,
shadow = Shadow(
radius = 18.dp,
color = neonColor,
spread = 3.dp,
),
),
)
}
}
冒頭の画像と同じ成果物
テキストもネオンにするには?(誤魔化し)
今回の dropShadow
と innerShadow
はあくまで Box
などの Compose に対して設定できるものなので、Text では従来通り Canvas で実装するか、下記のように Shadow (dropShadow に使用しているものとは別のクラス) を使用して誤魔化す方法もあります。
それでも枠線がそれなりにネオンっぽいのでぱっと見、誤魔化せている(いない)。
@Preview(showBackground = true, backgroundColor = 0xFF000000)
@Composable
fun NeonPreview() {
val neonColor = Color(0xFF0088ff)
val shape = RoundedCornerShape(size = 20.dp)
Box(contentAlignment = Alignment.Center) {
Box(
modifier = Modifier
.padding(20.dp)
.size(200.dp, 100.dp)
.dropShadow(
shape = shape,
shadow = Shadow(
radius = 12.dp,
color = neonColor,
spread = 3.dp,
),
)
.background(
color = Color.Black,
shape = shape,
)
.border(
width = 2.dp,
color = Color.White,
shape = shape,
)
.innerShadow(
shape = shape,
shadow = Shadow(
radius = 18.dp,
color = neonColor,
spread = 3.dp,
),
),
) {
Text(
text = "Hello world!",
style = TextStyle(
color = Color.White,
fontSize = 24.sp,
shadow = androidx.compose.ui.graphics.Shadow(
color = neonColor,
blurRadius = 20f,
),
),
modifier = Modifier.align(Alignment.Center),
)
}
}
}
テキスト付きネオン
雑感
今までは Canvas で実装するしかなかったのですが、簡単に実装できる API が置かれると嬉しいですね。
innerPadding
は background
に画像を設定するなどで表現の幅が増える気がします。
プロダクトに活用できるかは別としても様々なデザインを標準の API で実装できることで、さらなる表現が可能になると実装も捗りそうです。
Discussion