Home > database >  Jetpack compose custom shape with pie effect
Jetpack compose custom shape with pie effect

Time:10-05

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

CodePudding user response:

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)
)
  • Related