Welcome π
In this article, weβll create a cool animated Gender Sign in Jetpack Compose using Canvas.
Letβs dive in π
Support Classes
Before we begin implementing the icon, we need two support classes.
First, we need an enum
class GenderSign
to represent the sign options:
enum class GenderSign { MALE, FEMALE }
Second, we need a data
class GenderSignColors
to represent the color states for the different options:
data class GenderSignColors(
val maleSignColor: Color = Color.Blue,
val femaleSignColor: Color = Color.Red
)
Defining the Function
Alright, now we can define the function:
@Composable
fun AnimatedGenderSign(
genderSign: GenderSign,
modifier: Modifier = Modifier,
strokeWidth: Dp = 2.dp,
strokeCap: StrokeCap = StrokeCap.Butt,
colors: GenderSignColors = GenderSignColors(),
animDuration: Int = 350
)
Parameters
π― genderSign
π The current gender sign to display.
π― modifier
π Modifier to be applied to the Canvas layout.
π― strokeWidth
π Width of the stroke.
π― strokeCap
π Style of the stroke ends.
π― colors
π Colors for different sign options.
π― animDuration
π Animation duration in milliseconds.
Implementation
Animations
First, we need to animate two values based on the genderSign
parameter:
1οΈβ£ Progress Animation: This represents the overall progress of the animation, ranging from 0 to 1.
val progress by animateFloatAsState(
targetValue = when (genderSign) {
GenderSign.FEMALE -> 0f
GenderSign.MALE -> 1f
},
animationSpec = tween(animDuration)
)
2οΈβ£ Color Animation: This determines the color of the sign.
val color by animateColorAsState(
targetValue = when (genderSign) {
GenderSign.FEMALE -> colors.femaleSignColor
GenderSign.MALE -> colors.maleSignColor
},
animationSpec = tween(animDuration)
)
Canvas Drawing
Finally, we can draw the animated sign:
Canvas(modifier = modifier.size(24.dp)) {
// Get the width and height of the Canvas
val width = size.width
val height = size.height
// Calculate the radius of the circle and padding
val circleRadius = height * 0.24f
val padding = height * 0.1f
// Calculate the center of the circle with animation progress
val circleCenter = Offset(
x = width / 2,
y = circleRadius + padding + ((height / 2 - padding * 2) * progress)
)
// Create a Path for the gender sign
val genderSignPath = Path().apply {
// Add a circle to the Path
addOval(Rect(circleCenter, circleRadius))
// Add the core line
moveTo(x = circleCenter.x, y = circleCenter.y + circleRadius)
lineTo(x = circleCenter.x, y = circleCenter.y + circleRadius * 2)
// Add the lines for the arrowhead/cross
moveTo(x = circleCenter.x - circleRadius * 0.4f, y = circleCenter.y + circleRadius * 1.6f)
lineTo(x = circleCenter.x, y = circleCenter.y + circleRadius * 1.6f + (circleRadius * 0.4f * progress))
lineTo(x = circleCenter.x + circleRadius * 0.4f, y = circleCenter.y + circleRadius * 1.6f)
}
// Rotate and draw the Path
rotate(-135f * progress, circleCenter) {
drawPath(
path = genderSignPath,
color = color,
style = Stroke(
width = strokeWidth.toPx(),
cap = strokeCap
)
)
}
}
Congratulations π₯³! Weβve successfully built it π. You can find the full code on GitHub Gist π§βπ». Letβs explore the usage π
Practical Usage πββοΈ
Clickable Utility
To make the code cleaner, letβs define the clickableGenderSign
modifier:
fun Modifier.clickableGenderSign(
currentSign: GenderSign,
onSignChanged: (newSign: GenderSign) -> Unit
) = composed {
this.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
onClick = {
onSignChanged(
when (currentSign) {
GenderSign.MALE -> GenderSign.FEMALE
GenderSign.FEMALE -> GenderSign.MALE
}
)
}
)
}
Now, letβs see what weβve built π
val (sign, updatedSign) = remember { mutableStateOf(GenderSign.FEMALE) }
AnimatedGenderSign(
genderSign = sign,
strokeCap = StrokeCap.Round,
strokeWidth = 16.dp,
modifier = Modifier
.size(200.dp)
.clickableGenderSign(sign, updatedSign)
)
Output β¨
You might also like π
Thank you for reading this article! β€οΈ If you found it enjoyable and valuable, show your appreciation by clapping π and following Kappdev for more exciting articles π
π Subscribe to my π Email Notifications to stay updated with my latest content.
Happy coding!