I am trying to create a custom arc progress bar (S...
# compose
d
I am trying to create a custom arc progress bar (Semi circle). I am able to create one but I am not able to figure out how can I crop/ clip the Red box (whitespace) as shown in the screenshot. If I reduce the box height then the semi circle gets spoiled (shown in other screenshot). My code is in the thread.
c
@Devesh Sanghvi can you edit your post to put the code in this thread please? https://kotlinlang.slack.com/archives/CJLTWPH7S/p1616265877303000
1
d
Copy code
@Composable
fun ProgressBar(progress: Float) {
    Box(
        Modifier
            .fillMaxSize()
            .padding(8.dp)
            .drawBehind {
                drawArc(
                    color = Color.Blue,
                    startAngle = 180f,
                    sweepAngle = 180f,
                    useCenter = false,
                    style = Stroke(width = 20f)
                )
                drawArc(
                    color = Color.Green,
                    startAngle = 180f,
                    sweepAngle = progress * 180 / 100,
                    useCenter = false,
                    style = Stroke(width = 40f, cap = StrokeCap.Round)
                )
            }
            .clipToBounds()
    )
}

@Composable
fun ArcProgressBar(
    progress: Float = 50f,
    modifier: Modifier = Modifier
) {
    Box(
        modifier
            .size(200.dp, 100.dp)
    ) {
        Text(
            text = "${progress}%",
            style = MaterialTheme.typography.h4,
            modifier = Modifier.align(alignment = Alignment.Center)
        )

        ProgressBar(progress)
    }
}
n
Just needed to tweak the size of the arc that is being drawn.
drawArc
will automatically draw an ellipse that occupies the bounds of the drawing area. Because this arc is explicitly drawing a semi-circle starting at 9 o'clock, we needed to double the height of the arc being drawn to create as circular arc instead. Note the usage of the
size
parameter in the drawArc calls below:
Copy code
@Composable
fun ProgressBar(progress: Float) {
    Box(
        Modifier
            .fillMaxSize()
            .padding(8.dp)
            .drawBehind {
                drawArc(
                    color = Color.Blue,
                    size = Size(size.width, size.height * 2),
                    startAngle = 180f,
                    sweepAngle = 180f,
                    useCenter = false,
                    style = Stroke(width = 20f)
                )
                drawArc(
                    color = Color.Green,
                    size = Size(size.width, size.height * 2),
                    startAngle = 180f,
                    sweepAngle = progress * 180 / 100,
                    useCenter = false,
                    style = Stroke(width = 40f, cap = StrokeCap.Round)
                )
            }
            .clipToBounds()
    )
}
I took the original sample and added a background to better illustrate the bounds of the composable but this generates the following output
d
Interesting. For me it looks like this for original code with background. Which version of compose are you using?
n
Can you share your composable source? I am using the latest version of compose. Here's the entire composable source I was using. I would double check the size of the composable you are using since the gray background fully occupies the bounds of the composable. It looks like you are using the same size for the width/height:
Copy code
@Composable
fun ProgressBar(progress: Float) {
    Box(
        Modifier
            .fillMaxSize()
            .padding(8.dp)
            .drawBehind {
                drawArc(
                    color = Color.Blue,
                    size = Size(size.width, size.height * 2),
                    startAngle = 180f,
                    sweepAngle = 180f,
                    useCenter = false,
                    style = Stroke(width = 20f)
                )
                drawArc(
                    color = Color.Green,
                    size = Size(size.width, size.height * 2),
                    startAngle = 180f,
                    sweepAngle = progress * 180 / 100,
                    useCenter = false,
                    style = Stroke(width = 40f, cap = StrokeCap.Round)
                )
            }
            .clipToBounds()
    )
}
@Composable
fun ArcProgressBar(
    progress: Float = 50f,
    modifier: Modifier = Modifier
) {
    Box(
        modifier
            .size(200.dp, 100.dp)
    ) {
        Text(
            text = "${progress}%",
            style = MaterialTheme.typography.h4,
            modifier = Modifier.align(alignment = Alignment.BottomCenter)
        )
        ProgressBar(progress)
    }
}
d
Ahh I see what you are doing. I was using same height and width since you said you tried that on original code. Your code works very well. Thanks a lot. Half the box height and double the arc height is the trick. 🙂
👍 2