3

How i Draw Rectangle progress bar as a below in photo as CircleProgress indicator in android with JetpackCompose https://drive.google.com/file/d/1SXZcBp7uAesl-i6gHqFNXNpnc54Z6vdI/view?usp=share_link

CircularProgressIndicator(strokeWidth=10.dp,
                          progress = 1.0f,
                            color = Red,
                           modifier = Modifier.height(200.dp).width(200.dp).align(Alignment.Center))
Thracian
  • 43,021
  • 16
  • 133
  • 222

1 Answers1

6

You can change how to get progress for path progress i post an answer with 3 different alternatives

Result

enter image description here

First create a path and add Rounded rectangle

 if (path.isEmpty) {
                    path.addRoundRect(
                        RoundRect(
                            Rect(offset = Offset.Zero, size),
                            cornerRadius = CornerRadius(100.dp.toPx(), 100.dp.toPx())
                        )
                    )
                }

Then measure path using

    val pathMeasure by remember { mutableStateOf(PathMeasure()) }

            pathWithProgress.reset()

            pathMeasure.setPath(path, forceClosed = false)
            pathMeasure.getSegment(
                startDistance = 0f,
                stopDistance = pathMeasure.length * progress / 100f,
                pathWithProgress,
                startWithMoveTo = true
            )

Then draw this path and original Path as in implementation

@Preview
@Composable
private fun BorderProgressBar() {

    val startDurationInSeconds = 10
    var currentTime by remember {
        mutableStateOf(startDurationInSeconds)
    }

    var targetValue by remember {
        mutableStateOf(100f)
    }

    var timerStarted by remember {
        mutableStateOf(false)
    }
    LaunchedEffect(key1 = timerStarted) {
        if (timerStarted) {
            while (currentTime > 0) {
                delay(1000)
                currentTime--
            }
        }
    }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(40.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        // This is the progress path which wis changed using path measure
        val pathWithProgress by remember {
            mutableStateOf(Path())
        }

        // using path
        val pathMeasure by remember { mutableStateOf(PathMeasure()) }

        val path = remember {
            Path()
        }

        val progress by animateFloatAsState(
            targetValue = targetValue,
            animationSpec = tween(startDurationInSeconds * 1000, easing = LinearEasing)
        )

        Box(contentAlignment = Alignment.Center) {
            Canvas(modifier = Modifier.size(250.dp, 140.dp)) {

                if (path.isEmpty) {
                    path.addRoundRect(
                        RoundRect(
                            Rect(offset = Offset.Zero, size),
                            cornerRadius = CornerRadius(100.dp.toPx(), 100.dp.toPx())
                        )
                    )
                }
                pathWithProgress.reset()

                pathMeasure.setPath(path, forceClosed = false)
                pathMeasure.getSegment(
                    startDistance = 0f,
                    stopDistance = pathMeasure.length * progress / 100f,
                    pathWithProgress,
                    startWithMoveTo = true
                )


                clipPath(path) {
                    drawRect(Color.LightGray)
                }

                drawPath(
                    path = path,
                    style = Stroke(
                        6.dp.toPx()
                    ),
                    color = Color.Gray
                )

                drawPath(
                    path = pathWithProgress,
                    style = Stroke(
                        6.dp.toPx()
                    ),
                    color = Color.Blue
                )
            }

            Text(text = "$currentTime", fontSize = 40.sp, color = Color.Blue)
        }

        Spacer(modifier = Modifier.height(20.dp))
        Box(contentAlignment = Alignment.Center) {
            Canvas(modifier = Modifier.size(250.dp, 140.dp)) {

                if (path.isEmpty) {
                    path.addRoundRect(
                        RoundRect(
                            Rect(offset = Offset.Zero, size),
                            cornerRadius = CornerRadius(100.dp.toPx(), 100.dp.toPx())
                        )
                    )
                }
                pathWithProgress.reset()

                pathMeasure.setPath(path, forceClosed = false)
                pathMeasure.getSegment(
                    startDistance = 0f,
                    stopDistance = pathMeasure.length * progress.toInt() / 100f,
                    pathWithProgress,
                    startWithMoveTo = true
                )


                clipPath(path) {
                    drawRect(Color.LightGray)
                }

                drawPath(
                    path = path,
                    style = Stroke(
                        6.dp.toPx()
                    ),
                    color = Color.Gray
                )

                drawPath(
                    path = pathWithProgress,
                    style = Stroke(
                        6.dp.toPx()
                    ),
                    color = Color.Blue
                )
            }

            Text(text = "$currentTime", fontSize = 40.sp, color = Color.Blue)
        }

        Spacer(modifier = Modifier.height(20.dp))
        Box(contentAlignment = Alignment.Center) {
            Canvas(modifier = Modifier.size(250.dp, 140.dp)) {

                if (path.isEmpty) {
                    path.addRoundRect(
                        RoundRect(
                            Rect(offset = Offset.Zero, size),
                            cornerRadius = CornerRadius(100.dp.toPx(), 100.dp.toPx())
                        )
                    )
                }
                pathWithProgress.reset()

                pathMeasure.setPath(path, forceClosed = false)
                pathMeasure.getSegment(
                    startDistance = 0f,
                    stopDistance = pathMeasure.length * ((currentTime.toFloat() / startDurationInSeconds)),
                    pathWithProgress,
                    startWithMoveTo = true
                )


                clipPath(path) {
                    drawRect(Color.LightGray)
                }

                drawPath(
                    path = path,
                    style = Stroke(
                        6.dp.toPx()
                    ),
                    color = Color.Gray
                )

                drawPath(
                    path = pathWithProgress,
                    style = Stroke(
                        6.dp.toPx()
                    ),
                    color = Color.Blue
                )
            }

            Text(text = "$currentTime", fontSize = 40.sp, color = Color.Blue)
        }

        Button(
            modifier = Modifier.fillMaxWidth(),
            onClick = {
                targetValue = 0f
                timerStarted = true
            }) {
            Text(text = "Start Timer")
        }

        Text(
            text = "currentTime: $currentTime, " +
                    "progress: ${progress.toInt()}"
        )

    }
}
Thracian
  • 43,021
  • 16
  • 133
  • 222
  • The result is very commendable for your understanding. Can you share this drawing on github for me? – Đốc.tc Jun 30 '23 at 04:59
  • 1
    @Đốc.tc here you go. https://github.com/SmartToolFactory/Jetpack-Compose-Tutorials/blob/master/Tutorial1-1Basics/src/main/java/com/smarttoolfactory/tutorial1_1basics/chapter6_graphics/Tutorial6_13BorderProgressTimer.kt – Thracian Jun 30 '23 at 05:03