Android: compose drawArc would not get centered within `Box`

900 Views Asked by At

I am trying to show progress using drawArc for compose. I have tried drawBehind modifier to draw a background circle and not trying to draw another circle on top of it to show the progress. The problems is, no matter what I try, the arc turns out to be drawn at top left corner all the time. If I explicitly define the topLeft value, it only works for 1 screen size. So I am trying to get a dynamic size for both circles and also the strokewidth. So for Tablets only the circles should be increased depending on the screensize and also the thickness should be increased for the same. And for the smaller size devices, the value should be decreasing. Here is my code and output:

Column(
        modifier = Modifier
            .fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        BoxWithConstraints(
            Modifier
                .fillMaxSize()
                .background(Color.Yellow),
        ) {
            Canvas(modifier = Modifier
                .size(maxWidth, maxHeight)
                .background(color = Color.Red)) {
                drawCircle(
                    color = Color.Gray,
                    radius = (maxWidth /4).toPx(),
                    style = Stroke(width = 14f, cap = StrokeCap.Round),
                )
                val sweepAngle = progress/100 * 360
                drawArc(
                    size = Size((maxWidth/2).toPx(),(maxWidth/2).toPx()),
                    color = Color.Green,
                    startAngle = -90f,
                    sweepAngle = sweepAngle,
                    useCenter = false,
                    style = Stroke(10f, cap = StrokeCap.Round),
                )
            }
        }
    }

enter image description here

PS: I cannot use another circle object since I need to have the tip of the circle round aka cap should be Stroke.Round.

I ended up trying BoxWithConstraints so I can have access to maxWidth and maxHeight

1

There are 1 best solutions below

1
On BEST ANSWER

You have to calculate the topLeft offset of the arc as center of the circle - radius of the circle.
Then the size of arc is maxWidth/2 instead of maxWidth/4 = radius.

Something like:

            val stroke = 5.dp
            drawCircle(
                color = Color.Gray,
                radius = (maxWidth /4).toPx(),
                style = Stroke(width = stroke.toPx(), cap = StrokeCap.Round),
            )

            val sweepAngle = progress/100 * 360
            val offsetx = this.center.x - (maxWidth/4).toPx() 
            val offsety = this.center.y - (maxWidth/4).toPx() 

            drawArc(
                size = Size((maxWidth/2).toPx(),(maxWidth/2).toPx()),
                color = Color.Green,
                startAngle = 0f,
                sweepAngle = -sweepAngle,
                topLeft = Offset(offsetx,offsety),
                useCenter = false,
                style = Stroke(stroke.toPx(), cap = StrokeCap.Round),
            )
        }

enter image description here