https://kotlinlang.org logo
#compose
Title
# compose
d

Devesh Sanghvi

07/07/2021, 11:23 PM
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

Colton Idle

07/08/2021, 4:18 AM
@Devesh Sanghvi can you edit your post to put the code in this thread please? https://kotlinlang.slack.com/archives/CJLTWPH7S/p1616265877303000
1
d

Devesh Sanghvi

07/08/2021, 3:42 PM
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

Nader Jawad

07/08/2021, 8:43 PM
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

Devesh Sanghvi

07/08/2021, 10:07 PM
Interesting. For me it looks like this for original code with background. Which version of compose are you using?
n

Nader Jawad

07/08/2021, 10:10 PM
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

Devesh Sanghvi

07/08/2021, 10:15 PM
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
12 Views