Is there a way to have an Icon (with ImageVector) component with a shadow/elevation in Jetpack Compose?
I want to make an IconButton with an elevated Icon but there seems to be no solution available for this problem. Things like Modifier.shadow()
will only draw a shadow box around my icon and the Icon component itself has no elevation parameter.
This ticket seems like a duplicate of
CodePudding user response:
What you require is a library that converts imageVectors or xml files into Path
. As i know of there is no built-in library for this. There are probably few out there that converts into Path or Shape.
When you have a shape or path what you need to do is draw with this shape as Modifier or into Canvas
fun Modifier.vectorShadow(
path: Path,
x: Dp,
y: Dp,
radius: Dp
) = composed(
inspectorInfo = {
name = "vectorShadow"
value = path
value = x
value = y
value = radius
},
factory = {
val paint = remember {
Paint()
}
val frameworkPaint = remember {
paint.asFrameworkPaint()
}
val color = Color.DarkGray
val dx: Float
val dy: Float
val radiusInPx: Float
with(LocalDensity.current) {
dx = x.toPx()
dy = y.toPx()
radiusInPx = radius.toPx()
}
drawBehind {
this.drawIntoCanvas {
val transparent = color
.copy(alpha = 0f)
.toArgb()
frameworkPaint.color = transparent
frameworkPaint.setShadowLayer(
radiusInPx,
dx,
dy,
color
.copy(alpha = .7f)
.toArgb()
)
it.drawPath(path, paint)
}
}
}
)
Usage
Column(
modifier = Modifier
.fillMaxSize()
.padding(8.dp)
) {
val center = with(LocalDensity.current) {
150.dp.toPx()
}
val path1 = createPolygonPath(center, center, 6, center)
val path2 = createPolygonPath(center, center, 5, center)
Canvas(
modifier = Modifier
.size(300.dp)
.vectorShadow(path1, 0.dp, 0.dp, 6.dp)
.border(3.dp, Color.Green)
) {
drawPath(path1, Color.White)
}
Spacer(modifier = Modifier.height(10.dp))
Canvas(
modifier = Modifier
.size(300.dp)
.vectorShadow(path2, 3.dp, 3.dp, 10.dp)
.border(3.dp, Color.Green)
) {
drawPath(path2, Color.White)
}
}
Result
createPolygonPath is a sample function to create Path. If you manage to convert your vector to Path rest is simple.
fun createPolygonPath(cx: Float, cy: Float, sides: Int, radius: Float): Path {
val angle = 2.0 * Math.PI / sides
return Path().apply {
moveTo(
cx (radius * cos(0.0)).toFloat(),
cy (radius * sin(0.0)).toFloat()
)
for (i in 1 until sides) {
lineTo(
cx (radius * cos(angle * i)).toFloat(),
cy (radius * sin(angle * i)).toFloat()
)
}
close()
}
}
CodePudding user response:
It's not exactly what you want but for elevating an icon you can simply do this:
Icon(
Icons.Outlined.Refresh, contentDescription = "back",
modifier = Modifier
.size(300.dp)
.offset(10.dp, 10.dp), tint = Color(0, 0, 0, 40)
)
Icon(
Icons.Outlined.Refresh, contentDescription = "front",
modifier = Modifier.size(300.dp), tint = Color(0xFFb6d7a8)
)
The problem is that it is lacking the blurring effect.