You can change how to get progress for path progress i post an answer with 3 different alternatives
Result
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()}"
)
}
}