We all use emojis in our day-to-day life. Using canvas in Jetpack compose, we can draw various cool emojis!
Today we are going to implement 6 emojis in Jetpack compose. We will make use compose canvas to draw them.
At the end of this article, you will have a basic idea of how you can implement emojis shown below in your applications.
We are what we repeatedly do. Excellence, then, is not an act, but a habit. Try out Justly and start building your habits today!
To draw a confused emoji, we have used drawArc()
, drawCircle()
and drawline()
methods of canvas
.
Canvas(
modifier = Modifier
.padding(top = 16.dp)
.size(100.dp)
) {
drawArc(
color = Color(0xFFFFd301),
startAngle = 0f,
sweepAngle = 360f,
useCenter = true
)
drawCircle(
color = Color.White,
center = Offset(x = 35.dp.toPx(), y = 30.dp.toPx()),
radius = 30f,
)
drawCircle(
color = Color.Black,
center = Offset(-offsetX + 35.dp.toPx(), 30.dp.toPx()),
radius = 10f,
)
drawCircle(
color = Color.White,
center = Offset(x = 65.dp.toPx(), y = 30.dp.toPx()),
radius = 30f,
)
drawCircle(
color = Color.Black,
center = Offset(-offsetX + 65.dp.toPx(), 30.dp.toPx()),
radius = 10f,
)
drawLine(
start = Offset(x = 30.dp.toPx(), y = 70.dp.toPx()),
end = Offset(x = 70.dp.toPx(), y = 70.dp.toPx()),
color = Color.Black,
strokeWidth = 10.0f
)
}
Here,
drawArc()
is used to draw emoji circles.drawCircle()
methods at various points are used to draw eyesdrawLine()
at the end is used to show confused facial expressions.With this code snippet we will be able to draw our Confused emoji, but without eye movements (You can observe eye movement in mentioned gif).
Now, to move eyes on given offset values we can have something like —
val offsetX by animateValues(
values = listOf(0f, 15f, -15f, 0f),
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 1500, easing = easing),
repeatMode = RepeatMode.Restart
)
)
Here, our eyes will move on offsetX
in the range of (0f,15f,-15f,0f)
means 0f to -15f
, then -15f to 15f
and lastly from 15f to 0f
as we have used -offsetX
in the above code.
We can observe that animateValues
, which is a composable, will help us change the values based on target positions.
A typical animateValues
composable will look something like this. Just to note, we have already used this in our Jetpack compose progress animation article.
@Composable
fun animateValues(
values: List<Float>,
animationSpec: AnimationSpec<Float> = spring(),
): State<Float> {
// 1. Create the groups zipping with next entry
val groups by rememberUpdatedState(newValue = values.zipWithNext())
// 2. Start the state with the first value
val state = remember { mutableStateOf(values.first()) }
LaunchedEffect(key1 = groups) {
val (_, setValue) = state
// Start the animation from 0 to groups quantity
animate(
initialValue = 0f,
targetValue = groups.size.toFloat(),
animationSpec = animationSpec,
) { frame, _ ->
// Get which group is being evaluated
val integerPart = frame.toInt()
val (initialValue, finalValue) = groups[frame.toInt()]
// Get the current "position" from the group animation
val decimalPart = frame - integerPart
// Calculate the progress between the initial and final value
setValue(
initialValue + (finalValue - initialValue) * decimalPart
)
}
}
return state
}
The complete composable for confused emoji is available on Github.
To draw a happy emoji, we have used drawArc()
, drawCircle()
and drawPath()
methods of canvas in Jetpack compose.
drawArc(
color = Color(0xFFFFd301),
startAngle = 0f,
sweepAngle = 360f,
useCenter = true
)
drawCircle(
color = Color.White,
center = Offset(x = 35.dp.toPx(), y = 30.dp.toPx()),
radius = 30f,
)
val mouthPath = Path().let {
it.moveTo(size * 0.22.dp.toPx(), size * 0.70.dp.toPx())
it.quadraticBezierTo(
size * 0.50.dp.toPx(), size * 0.80.dp.toPx(),
size * 0.78.dp.toPx(), size * 0.70.dp.toPx()
)
it.quadraticBezierTo(
size * 0.50.dp.toPx(), size * 0.95.dp.toPx(),
size * 0.22.dp.toPx(), size * 0.70.dp.toPx()
)
it.close()
it
}
drawPath(path = mouthPath, color = Color.Black)
Here,
drawArc()
is used to draw emoji circlesdrawCircle()
methods at various points are used to draw eyesdrawPath()
at the end is used to show happy facial expressions.To draw a happy facial path:
The complete composable for happy emoji is available on Github.
To draw a cool emoji, we have again used drawArc()
, drawCircle()
and drawPath()
methods of canvas in Jetpack compose.
drawArc(
color = Color(0xFFFFd301),
startAngle = 0f,
sweepAngle = 360f,
useCenter = true
)
drawCircle(
color = Color.White,
center = Offset(x = 65.dp.toPx(), y = 30.dp.toPx()),
radius = 20f,
)
val mouthPath = Path().let {
it.moveTo(size * 0.20.dp.toPx(), size * 0.70.dp.toPx())
it.quadraticBezierTo(
size * 0.50.dp.toPx(), size * 0.80.dp.toPx(),
size * 0.78.dp.toPx(), size * 0.70.dp.toPx()
)
it.quadraticBezierTo(
size * 0.50.dp.toPx(), size * 1.60.dp.toPx(),
size * 0.20.dp.toPx(), size * 0.70.dp.toPx()
)
it.close()
it
}
drawPath(path = mouthPath, color = TongueColor)
Here,
drawArc()
is used to draw emoji circle.drawCircle()
methods at various points are used to draw eyesdrawPath()
at the end is used to show tongue expressions.Here, we have kept the right eye of our emoji a bit smaller intentionally. Follow the happy emoji mouth path steps to draw a tongue of emoji.
The complete composable for cool emoji is available on Github.
To draw an exclamation emoji, we have once again used drawArc()
, drawCircle()
methods of canvas in Jetpack compose.
Canvas(
modifier = Modifier
.padding(top = 40.dp)
.size(100.dp)
) {
drawArc(
color = Color(0xFFFFd301),
startAngle = 0f,
sweepAngle = 360f,
useCenter = true
)
drawCircle(
color = Color.White,
center = Offset(x = 35.dp.toPx(), y = 30.dp.toPx()),
radius = eyeAnimation,
)
drawCircle(
color = Color.Black,
center = Offset(x = 35.dp.toPx(), y = 30.dp.toPx()),
radius = 10f,
)
drawCircle(
color = Color.White,
center = Offset(x = 65.dp.toPx(), y = 30.dp.toPx()),
radius = eyeAnimation,
)
drawCircle(
color = Color.Black,
center = Offset(x = 65.dp.toPx(), y = 30.dp.toPx()),
radius = 10f,
)
drawCircle(
color = ExclamationEmojiColor,
center = Offset(x = 50.dp.toPx(), y = 70.dp.toPx()),
radius = 20f,
)
}
Here,
drawArc()
is used to draw emoji circle.drawCircle()
methods at various points are used to draw eyesWith this code snippet, we will be able to draw our Exclamation emoji, but without eye animation.
Now, to zoom eyes we can have something like:
val infiniteTransition = rememberInfiniteTransition()
Here, we have used infiniteTransition
and we remember it to save it in compose memory across composables.
We can use animateFloat
to create the animation of type float that runs infinitely as a part of infiniteTransition
.
Once the animation is created it will run from the initial value (1f) to the target value (30f) and will repeat forever.
val eyeAnimation by infiniteTransition.animateFloat(
initialValue = 1f,
targetValue = 30f,
animationSpec = infiniteRepeatable(
animation = tween(1500, easing = FastOutSlowInEasing),
repeatMode = RepeatMode.Reverse
)
)
Here, we have used tween as a duration-based AnimationSpec
and it uses easing to adjust the animation’s fraction.
Easing allows the animating value to speed up and slow down, rather than moving at a constant speed.
Tween also has another parameter called durationMills
which is the waiting period after each iteration of our animation(we have used 1500 in the Twin animation example).
That’s it for zooming emoji’s eyes.
The complete composable for exclamation emoji is available on Github.
To draw a long tongue emoji we have used drawArc()
, drawOval()
and drawPath()
methods of canvas in Jetpack compose.
drawArc(
color = Color(0xFFFFd301),
startAngle = 0f,
sweepAngle = 360f,
useCenter = true
)
drawOval(
color = EmojiEyeColor,
topLeft = Offset(x = 65.dp.toPx(), y = 30.dp.toPx()),
size = Size(20f, 35f)
)
val mouthPath = Path().let {
it.moveTo(size * 0.20.dp.toPx(), size * 0.70.dp.toPx())
it.quadraticBezierTo(
size * 0.50.dp.toPx(), size * 0.80.dp.toPx(),
size * 0.78.dp.toPx(), size * 0.70.dp.toPx()
)
it.quadraticBezierTo(
size * 0.50.dp.toPx(), size * 1.90.dp.toPx(),
size * 0.20.dp.toPx(), size * 0.70.dp.toPx()
)
it.close()
it
}
drawPath(path = mouthPath, color = TongueColor)
Here,
drawArc()
is used to draw emoji circle.drawOval()
methods at various points are used to draw eyesdrawPath()
at the end is used to show long tongue expressions.To draw a long tongue of emoji, you can follow happy emoji mouth path steps.
The complete composable for long tongue emoji is available on Github.
To draw a sad emoji we have used drawArc()
, drawOval()
and drawPath()
methods of canvas in Jetpack compose.
drawArc(
color = Color(0xFFFFd301),
startAngle = 0f,
sweepAngle = 360f,
useCenter = true
)
drawOval(
color = EmojiEyeColor,
topLeft = Offset(x = 65.dp.toPx(), y = 30.dp.toPx()),
size = Size(20f, 35f)
)
val mouthPath = Path().let {
it.moveTo(size * 0.30.dp.toPx(), size * 0.70.dp.toPx())
it.quadraticBezierTo(
size * 0.45.dp.toPx(), size * 0.45.dp.toPx(),
size * 0.65.dp.toPx(), size * 0.65.dp.toPx()
)
it.quadraticBezierTo(
size * 0.45.dp.toPx(), size * 0.35.dp.toPx(),
size * 0.30.dp.toPx(), size * 0.70.dp.toPx()
)
it.close()
it
}
drawPath(path = mouthPath, color = TongueColor)
Here:-
drawArc()
is used to draw emoji circledrawOval()
methods at various points are used to draw eyes anddrawPath()
at the end is used to show sad expressions.To draw a sad emoji mouth expressions, you can follow happy emoji mouth path steps.
The complete composable for sad emoji is available on Github.
That’s it for all the Emojis, hope you learned something new!
You will have a basic idea of how Canvas works and how to make use of its basic functions to draw various shapes. You will also have an idea about how to animate shapes on Canvas using various animation functions.
Don’t worry if you didn’t get all the emojis. You can find the complete source code of all the above animations on Github.
As always, feedback and suggestions are welcome. Feel free to add them in the response section.