Last active
May 16, 2025 18:37
-
-
Save Andrew0000/3edb9c25ebc20a2935c9ff4805e05f5d to your computer and use it in GitHub Desktop.
Jetpack Compose custom shadow with dx, dy and radius
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.graphics.BlurMaskFilter | |
import androidx.compose.foundation.background | |
import androidx.compose.foundation.layout.Box | |
import androidx.compose.foundation.layout.fillMaxSize | |
import androidx.compose.foundation.layout.padding | |
import androidx.compose.foundation.layout.requiredSize | |
import androidx.compose.runtime.Composable | |
import androidx.compose.runtime.remember | |
import androidx.compose.ui.Modifier | |
import androidx.compose.ui.composed | |
import androidx.compose.ui.draw.drawBehind | |
import androidx.compose.ui.graphics.Color | |
import androidx.compose.ui.graphics.Paint | |
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas | |
import androidx.compose.ui.graphics.toArgb | |
import androidx.compose.ui.platform.LocalDensity | |
import androidx.compose.ui.tooling.preview.Preview | |
import androidx.compose.ui.unit.Dp | |
import androidx.compose.ui.unit.dp | |
@Preview( | |
widthDp = 160, | |
heightDp = 160, | |
showBackground = true, | |
backgroundColor = 0xffffff, | |
) | |
@Composable | |
private fun Preview() { | |
Box( | |
modifier = Modifier | |
.requiredSize(100.dp) | |
.background(Color.Yellow), | |
) { | |
Box( | |
modifier = Modifier | |
.fillMaxSize() | |
.padding(25.dp) | |
.shadowCustom( | |
offsetX = 8.dp, | |
offsetY = 8.dp, | |
blurRadius = 8.dp, | |
), | |
) { | |
Box( | |
modifier = Modifier | |
.fillMaxSize() | |
.background(Color.Green), | |
) { | |
} | |
} | |
} | |
} | |
fun Modifier.shadowCustom( | |
color: Color = Color.Black, | |
offsetX: Dp = 0.dp, | |
offsetY: Dp = 0.dp, | |
blurRadius: Dp = 0.dp, | |
shapeRadius: Dp = 0.dp, | |
) = composed { | |
val paint: Paint = remember { Paint() } | |
val blurRadiusPx = blurRadius.px(LocalDensity.current) | |
val maskFilter = remember { | |
BlurMaskFilter(blurRadiusPx, BlurMaskFilter.Blur.NORMAL) | |
} | |
drawBehind { | |
drawIntoCanvas { canvas -> | |
val frameworkPaint = paint.asFrameworkPaint() | |
if (blurRadius != 0.dp) { | |
frameworkPaint.maskFilter = maskFilter | |
} | |
frameworkPaint.color = color.toArgb() | |
val leftPixel = offsetX.toPx() | |
val topPixel = offsetY.toPx() | |
val rightPixel = size.width + leftPixel | |
val bottomPixel = size.height + topPixel | |
if (shapeRadius > 0.dp) { | |
val radiusPx = shapeRadius.toPx() | |
canvas.drawRoundRect( | |
left = leftPixel, | |
top = topPixel, | |
right = rightPixel, | |
bottom = bottomPixel, | |
radiusX = radiusPx, | |
radiusY = radiusPx, | |
paint = paint, | |
) | |
} else { | |
canvas.drawRect( | |
left = leftPixel, | |
top = topPixel, | |
right = rightPixel, | |
bottom = bottomPixel, | |
paint = paint, | |
) | |
} | |
} | |
} | |
} | |
private fun Dp.px(density: Density): Float = | |
with(density) { toPx() } | |
@Andrew0000 thanks It's help me to give shadow to NavigationBar
Thank you for making this! I modified it to work with Jetpack Compose shapes for my project.
fun Modifier.shadowCustom(
color: Color = Color.Black,
offsetX: Dp = 0.dp,
offsetY: Dp = 0.dp,
blurRadius: Dp = 0.dp,
shape: Shape = RectangleShape,
) = composed {
require(blurRadius > 0.dp) { "Blur radius must be greater than 0" }
val paint: Paint = remember { Paint() }
val blurRadiusPx = blurRadius.toPx(LocalDensity.current)
val offsetXpx = offsetX.toPx(LocalDensity.current)
val offsetYpx = offsetY.toPx(LocalDensity.current)
val maskFilter = remember {
BlurMaskFilter(blurRadiusPx, BlurMaskFilter.Blur.NORMAL)
}
drawBehind {
drawIntoCanvas { canvas ->
val frameworkPaint = paint.asFrameworkPaint()
if (blurRadius != 0.dp) {
frameworkPaint.maskFilter = maskFilter
}
frameworkPaint.color = color.toArgb()
val outline = shape.createOutline(size, LayoutDirection.Ltr, this)
// Apply the offset by translating the canvas
canvas.save()
canvas.translate(offsetXpx, offsetYpx)
canvas.drawOutline(
outline = outline,
paint = paint
)
canvas.restore()
}
}
}
private fun Dp.toPx(density: Density): Float = with(density) { toPx() }
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@qixiaoo Yes, thank you. I updated the gist