1

I want to make a shape filling the circle according to given percentage. Since i suck at math I'm unable to achieve this with path Api of jetpack compose.

My custom class is looking like this:

class ProgressPie(val progress: Float) : Shape {
override fun createOutline(
    size: Size,
    layoutDirection: LayoutDirection,
    density: Density
): Outline {
    val path = Path().apply {
        addArc(
            Rect(0f, 0f, size.width , size.height ),
            -90f,
            360f * progress
        )
        close()
    }
    return Outline.Generic(path)
}

}

and when the progress parameter changed the result should be looking like this.

enter image description here

David L.
  • 25
  • 1
  • 6

1 Answers1

1

You can use Canvas or Modifier.draWithContent to draw a pie chart.

Column(modifier=Modifier.padding(10.dp)) {
    var progress by remember { mutableStateOf(0f) }
    Box(
        modifier = Modifier
            .background(Color.White)
            .fillMaxWidth()
            .aspectRatio(1f)
            .drawBehind {
                drawCircle(Color.LightGray, style = Stroke(1.dp.toPx()))
                drawArc(
                    Color.Blue,
                    startAngle = -90f,
                    sweepAngle = progress,
                    useCenter = true
                )
            }
    )

    Slider(
        value = progress,
        onValueChange = {
            progress = it
        },
        valueRange = 0f..360f
    )
}

You can use shape with remember to create new shape on progress change but the issue with Path and arc is it's not drawn from center.

 val shape = remember(progress) {
    GenericShape { size: Size, _: LayoutDirection ->
        if( progress == 360f){
            addOval(
                Rect(0f, 0f, size.width, size.height)
            )
        }else {
            moveTo(size.width/2f, size.height/2f)
            arcTo(
                Rect(0f, 0f, size.width, size.height),
                -90f,
                progress,
                forceMoveTo = false
            )
        }
        close()
    }
}

Box(
    modifier = Modifier
        .fillMaxWidth()
        .background(Color.White)
        .clip(shape)
        .background(Color.Blue)
        .aspectRatio(1f)
)
Thracian
  • 43,021
  • 16
  • 133
  • 222
  • thanks for the answer @Thracian. As you mention arcTo function doesn't draw from the center and I have no idea how to do it. I need this a shape because I will use it to clip another composable. – David L. Oct 04 '22 at 16:22
  • 1
    Yeah. You need to use `addOval` when angle is 360f or it shows nothing. Updated answer adds an oval to have pie chart in every progress value – Thracian Oct 04 '22 at 16:23
  • Thanks for the update. This line fixed it moveTo(size.width/2f, size.height/2f). – David L. Oct 04 '22 at 17:28