Jetpack Compose Canvas (with Examples)

Jetpack Compose Canvas

Jetpack Compose offers several APIs (like Button, Switch, etc.) to create awesome-looking apps. But what if you want to create a custom UI? That’s where Canvas comes in handy. Today, we will learn how to draw custom graphics in Jetpack Compose using Canvas API.

Prerequisites:

What is Canvas?

Canvas is used to create custom UI components. You can design any kind of UI you want. Look at these awesome progress bars. Most of them are made with Canvas API.

Before jumping into Canvas, we need to understand the coordinate system in Android.

Canvas Coordinate system

The coordinate system starts at the top left corner. The corner represents the (0,0) point. The X values increase towards the right and Y values increase downwards.

Everything we draw on the Canvas is relative to (0,0) point.

How to Use Canvas in Jetpack Compose?

Jetpack Compose offers Canvas API. It takes two parameters.

@Composable
fun Canvas(modifier: Modifier, onDraw: DrawScope.() -> Unit)

The modifier is used for adding styles (like border) and onDraw is a lambda that will be called when we are drawing. Let’s create a Canvas of size 300.dp.

@Composable
fun MyUI() {
    Canvas(
        modifier = Modifier
            .size(size = 300.dp)
            .border(width = 2.dp, color = Color.Magenta, shape = RectangleShape)
    ) {

    }
}

It looks like this:

Graphics

Let’s specify the coordinates at the corners.

Coordinates corners

Let’s draw a line vertically. To draw lines, there is a drawLine() function.

@Composable
fun MyUI() {
    Canvas(
        modifier = Modifier
            .size(size = 300.dp)
            .border(width = 2.dp, color = Color.Magenta, shape = RectangleShape)
    ) {
        drawLine(
            color = Color.Blue,
            strokeWidth = 2.dp.toPx(),
            start = Offset(x = size.width/2, y = 0f),
            end = Offset(x = size.width/2, y = size.height)
        )
    }
}

Output:

Canvas draw line

Let’s understand the code.

There are 4 parameters.

color – line color
strokeWidth – width of the line
start – first point of the line
end – last point of the line

We have specified the first and last points using the Offset() function. The function takes two parameters – x and y. x represents the x coordinate and y represents the y coordinate.

Our line starts at the top center and ends at the bottom center. The coordinates look like this:

line start end positions

We can get the Canvas size from the size property. size.height returns the height and size.width returns the width.

The start position is at the center of the x – axis. So, the x should be 150.dp (size.width/2), and the y should be 0.dp.

The end position is at the bottom center. So, the x should be 150.dp (size.width/2), and the y should be 300.dp (size.height).

Similar to drawLine(), there are other drawing functions:

Note: You can also draw some basic shapes using the box with round corner shape API.

Jetpack Compose Draw Behind:

Jetpack Compose offers another API called Modifier.drawBehind. It helps us to draw shapes behind other composables.

Example:

@Composable
fun MyUI() {
    Box(modifier = Modifier
        .size(size = 300.dp)
        .border(width = 2.dp, color = Color.Magenta, shape = RectangleShape)
        .drawBehind {
            // draw here
            drawLine(
                color = Color.Blue,
                strokeWidth = 2.dp.toPx(),
                start = Offset(x = size.width / 2, y = 0f),
                end = Offset(x = size.width / 2, y = size.height)
            )
        }
    )
}

Output:

Canvas draw line

When working with Canvas, you need to remember 2 things:

1. If the element’s size is bigger than the canvas’s, it goes outside the canvas.

@Composable
fun MyUI() {
    Canvas(
        modifier = Modifier
            .size(size = 100.dp)
            .border(width = 2.dp, color = Color.Magenta)
    ) {
        drawCircle(
            color = Color.Green.copy(alpha = 0.1f),
            radius = 110.dp.toPx() // bigger than Canvas
        )
    }
}

Output:

Jetpack Compose Canvas boundaries

The circle is crossing the Canvas.

2. Whenever you want to set the size, use dp.toPx() instead of float values. It ensures that your UI is consistent across all the screen densities.

This is all about Canvas in Jetpack Compose. I hope you have learned something new. If you have any doubts, comment below.

Continue Exploring Jetpack Compose:

References:

Leave a Comment