
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
)
color – Color 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.
blendMode – Blending 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:

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:

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

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:
How to detect click on each Arch
You can use Modifier.pointerInput(). https://stackoverflow.com/a/68401669/14309684
Hi, thanks for the great article! Now I finally understood how to use arcs, and listen to clicks. Is there any kind of animation for arcs? I would like to draw a chart but to “paint” the sweepAngle with an animation, or make a chronometer using the style stroke to draw a circle and decrease it in a parameterized time.
Yes. You can use any animation API. Look at this example: http://semicolonspace.com/circular-progressbar-android-compose/