How to Draw an Arc in Jetpack Compose Canvas?

Jetpack Compose draw arc

Today, we’ll learn how to draw an arc in Jetpack Compose using the drawArc method of Canvas.

Prerequisites:

For this article, create an empty Jetpack Compose project and open MainActivity. Create a composable called MyUI() and call it from the onCreate().

// we need the following packages
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.unit.dp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            YourProjectNameTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background
                ) {
                    Column(
                        modifier = Modifier.fillMaxSize(),
                        verticalArrangement = Arrangement.Center,
                        horizontalAlignment = Alignment.CenterHorizontally
                    ) {
                        MyUI()
                    }
                }
            }
        }
    }
}

@Composable
fun MyUI() {

}

We’ll write our code in the MyUI().

The drawArc() method looks like this:

fun drawArc(
    color: Color,
    startAngle: Float,
    sweepAngle: Float,
    useCenter: Boolean,
    topLeft: Offset = Offset.Zero,
    size: Size = this.size.offsetSize(topLeft),
    /*@FloatRange(from = 0.0, to = 1.0)*/
    alpha: Float = 1.0f,
    style: DrawStyle = Fill,
    colorFilter: ColorFilter? = null,
    blendMode: BlendMode = DefaultBlendMode
)

colorColor of the arc.

startAngle – Starting angle in degrees. 0f represents 3 o’clock.

sweepAngle – Represents the size of the arc in degrees. It is drawn relative to startAngle.

useCenter – It indicates if the arc is to close the center of the bounds.

topLeft – Offset value. Look at the Canvas article for more information.

size – We can change the arc size (like we can make it smaller or larger).

alpha – Opacity value of the arc. It ranges from 0f to 1f. 0f represents fully transparent, and 1f represents fully opaque.

style – Whether or not the arc is stroked or filled in.

colorFilter – It is used to modify each pixel of the arc.

blendModeBlending algorithm to be applied to the arc when it is drawn.

Let us understand the parameters with examples.

First, let’s create a Canvas of size 300.dp.

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

    }
}

Output:

Canvas dp

Here is a simple arc:

@Composable
fun MyUI() {
    Canvas(
        modifier = Modifier
            .size(size = 300.dp)
            .border(color = Color.Magenta, width = 2.dp)
    ) {
        drawArc(
            color = Color.Cyan,
            startAngle = 0f,
            sweepAngle = 90f,
            useCenter = true
        )
    }
}

Output:

draw arc

Note: Angles with positive values travel in the clockwise direction. Angles with negative values go in the anti-clockwise direction.

In the above output:

start and sweep angles

The startAngle 0f represents 3 o’clock. You can take it as a reference. The sweepAngle 90f is drawn relative to the startAngle.

Let’s play with the angles.

Example 1:

startAngle = 90f
sweepAngle = 180f

@Composable
fun MyUI() {
    Canvas(
        modifier = Modifier
            .size(size = 300.dp)
            .border(color = Color.Magenta, width = 2.dp)
    ) {
        drawArc(
            color = Color.Cyan,
            startAngle = 90f,
            sweepAngle = 180f,
            useCenter = true
        )
    }
}

Output:

startAngle 90f sweepAngle 180f

Example 2:

startAngle = -90f
sweepAngle = 180f

@Composable
fun MyUI() {
    Canvas(
        modifier = Modifier
            .size(size = 300.dp)
            .border(color = Color.Magenta, width = 2.dp)
    ) {
        drawArc(
            color = Color.Cyan,
            startAngle = -90f,
            sweepAngle = 180f,
            useCenter = true
        )
    }
}

Output:

startAngle negative

Example 3:

startAngle = -45f
sweepAngle = -90f

@Composable
fun MyUI() {
    Canvas(
        modifier = Modifier
            .size(size = 300.dp)
            .border(color = Color.Magenta, width = 2.dp)
    ) {
        drawArc(
            color = Color.Cyan,
            startAngle = -45f,
            sweepAngle = -90f,
            useCenter = true
        )
    }
}

Output:

draw arc negative values

Example 4:

startAngle = 45f
sweepAngle = -90f

@Composable
fun MyUI() {
    Canvas(
        modifier = Modifier
            .size(size = 300.dp)
            .border(color = Color.Magenta, width = 2.dp)
    ) {
        drawArc(
            color = Color.Cyan,
            startAngle = 45f,
            sweepAngle = -90f,
            useCenter = true
        )
    }
}

Output:

angles

The useCenter parameter indicates if the arc should be close to the center. If we set it to false in the above code, it becomes:

@Composable
fun MyUI() {
    Canvas(
        modifier = Modifier
            .size(size = 300.dp)
            .border(color = Color.Magenta, width = 2.dp)
    ) {
        drawArc(
            color = Color.Cyan,
            startAngle = 45f,
            sweepAngle = -90f,
            useCenter = false
        )
    }
}

Output:

useCenter

In Canvas, everything is drawn relative to (0,0) which is the top left corner. We can change this relative point using the topLeft parameter.

Example:

With default topLeft:

@Composable
fun MyUI() {
    Canvas(
        modifier = Modifier
            .size(size = 300.dp)
            .border(color = Color.Magenta, width = 2.dp)
    ) {
        drawArc(
            color = Color.Cyan,
            startAngle = 180f,
            sweepAngle = 90f,
            useCenter = true
        )
    }
}

Output:

top left canvas

Let’s change it to the center of the canvas:

@Composable
fun MyUI() {
    Canvas(
        modifier = Modifier
            .size(size = 300.dp)
            .border(color = Color.Magenta, width = 2.dp)
    ) {
        drawArc(
            color = Color.Cyan,
            startAngle = 180f,
            sweepAngle = 90f,
            useCenter = true,
            topLeft = Offset(x = 150.dp.toPx(), y = 150.dp.toPx())
        )
    }
} 

Output:

topLeft center

We can change the size of the arc using the size parameter:

@Composable
fun MyUI() {
    Canvas(
        modifier = Modifier
            .size(size = 300.dp)
            .border(color = Color.Magenta, width = 2.dp)
    ) {
        drawArc(
            color = Color.Cyan,
            startAngle = 180f,
            sweepAngle = 90f,
            useCenter = true,
            size = Size(width = 100.dp.toPx(), height = 100.dp.toPx())
        )
    }
}

Output:

draw arc size

There is another variation of the drawArc method that accepts brush instead of color. We can draw gradient backgrounds using it.

@Composable
fun MyUI() {
    Canvas(
        modifier = Modifier
            .size(size = 300.dp)
            .border(color = Color.Magenta, width = 2.dp)
    ) {
        drawArc(
            brush = Brush.horizontalGradient(colors = listOf(Color.Yellow, Color.Green)),
            startAngle = 180f,
            sweepAngle = 90f,
            useCenter = true
        )
    }
}

Output:

gradient arc

drawArc accepts a parameter called style. We can create a stroked arc using it.

@Composable
fun MyUI() {
    Canvas(
        modifier = Modifier
            .size(size = 300.dp)
            .border(color = Color.Magenta, width = 2.dp)
    ) {
        drawArc(
            brush = Brush.horizontalGradient(colors = listOf(Color.Yellow, Color.Green)),
            startAngle = 180f,
            sweepAngle = 90f,
            useCenter = true,
            topLeft = Offset(x = 20.dp.toPx(), y = 20.dp.toPx()),
            style = Stroke(width = 8.dp.toPx())
        )
    }
}

Output:

Jetpack compose arc stroke

This is all about drawing an arc in Jetpack Compose using the Canvas drawArc method. I hope you have learned something new. If you have any doubts, comment below.

Related Articles:

4 thoughts on “How to Draw an Arc in Jetpack Compose Canvas?”

Leave a Comment