Lokik Soni
08/15/2022, 6:28 PMprivate val StrokeWidth = 15.dp
/**
* Circular progressBar with centered
* [title], [progress] and [icon].
*
* @author Lokik Soni
*/
@Composable
fun CircularProgressIndicator(
modifier: Modifier = Modifier,
title: String,
progress: Float,
progressColor: Brush = Brush.linearGradient(MaterialTheme.gradientColors.GradientCyan),
icon: ImageVector,
iconColor: Color = MaterialTheme.colors.primary,
backgroundColor: Color = MaterialTheme.colors.surface,
radius: Dp = 110.dp
) {
val pxRadius = LocalDensity.current.run { radius.toPx() }
val pxStroke = LocalDensity.current.run { StrokeWidth.toPx() }
val animatedProgress by animateFloatAsState(
targetValue = 3.6f * progress,
animationSpec = tween(Constants.DURATION_MILLIS, easing = LinearEasing)
)
Box(
modifier = modifier
.background(Color.Green)
.size((pxRadius + pxStroke).dp),
contentAlignment = Alignment.Center
) {
Canvas(
modifier = Modifier
.matchParentSize(),
) {
inset(size.width / 2 - pxRadius, size.height / 2 - pxRadius) {
drawArc(
brush = progressColor,
startAngle = -90f,
sweepAngle = animatedProgress,
useCenter = false,
style = Stroke(width = StrokeWidth.toPx(), cap = StrokeCap.Round),
blendMode = BlendMode.SrcIn,
)
drawCircle(
color = backgroundColor,
radius = pxRadius,
center = center,
)
}
}
Column(
modifier = Modifier.size(pxRadius.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceEvenly
) {
Text(
text = title,
style = MaterialTheme.typography.overline
)
Text(
text = "${progress.toInt()}%",
style = MaterialTheme.typography.h4
)
IconWithBackground(
icon = icon,
color = iconColor,
description = title
)
}
}
}
Doris Liu
08/15/2022, 8:12 PM(pxRadius + pxStroke).dp
is not density independent, because the earlier val pxRadius = LocalDensity.current.run { radius.toPx() }
. I suspect you meant to use toDp()
instead.Lokik Soni
08/16/2022, 3:50 PMsize(radius + progressWidth)
dp version in BOX.
fun CircularProgressIndicator(
modifier: Modifier = Modifier,
radius: Dp = 200.dp,
title: String,
progress: Float,
progressWidth: Dp = 25.dp,
progressColor: Brush = Brush.linearGradient(MaterialTheme.gradientColors.GradientCyan),
icon: ImageVector,
iconColor: Color = MaterialTheme.colors.primary,
backgroundColor: Color = MaterialTheme.colors.surface,
) {
val pxRadius = LocalDensity.current.run { radius.toPx() }
val animatedProgress by animateFloatAsState(
targetValue = 3.6f * progress,
animationSpec = tween(Constants.DURATION_MILLIS, easing = LinearEasing)
)
Box(
modifier = modifier
.background(Color.Green)
.size(radius + progressWidth),
contentAlignment = Alignment.Center
) {
Canvas(
modifier = Modifier
.matchParentSize(),
) {
inset((size.width - pxRadius) / 2, (size.height - pxRadius) / 2) {
drawArc(
brush = progressColor,
startAngle = -90f,
sweepAngle = animatedProgress,
useCenter = false,
style = Stroke(width = progressWidth.toPx() / 2, cap = StrokeCap.Round),
blendMode = BlendMode.SrcIn,
)
drawCircle(
color = backgroundColor,
radius = pxRadius / 2.0f,
center = center,
)
}
}
Column(
modifier = Modifier.size(radius),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceEvenly
) {
Text(
text = title,
style = MaterialTheme.typography.overline
)
Text(
text = "${progress.toInt()}%",
style = MaterialTheme.typography.h4
)
IconWithBackground(
icon = icon,
color = iconColor,
description = title
)
}
}
}
Internally drawCircle was dividing radius by 2 so I also thought to divide it and it worked.
Thank you @Doris Liu