d

    Devesh Sanghvi

    1 year ago
    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.
    Colton Idle

    Colton Idle

    1 year ago
    @Devesh Sanghvi can you edit your post to put the code in this thread please? https://kotlinlang.slack.com/archives/CJLTWPH7S/p1616265877303000
    d

    Devesh Sanghvi

    1 year ago
    @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)
        }
    }
    Nader Jawad

    Nader Jawad

    1 year ago
    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:
    @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

    1 year ago
    Interesting. For me it looks like this for original code with background. Which version of compose are you using?
    Nader Jawad

    Nader Jawad

    1 year ago
    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:
    @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

    1 year ago
    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. 🙂