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

Lokik Soni

08/15/2022, 6:28 PM
Why I am getting different design in two different phone of different size. According to me the green box size should be same as my circularProgress like in left image.
👍 1
Copy code
private 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
            )
       }
    }
}
d

Doris Liu

08/15/2022, 8:12 PM
One possible cause for that is the size defined using dp conversion
(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.
l

Lokik Soni

08/16/2022, 3:50 PM
Solved by dividing the pxRadius by 2 where it is used and used
size(radius + progressWidth)
dp version in BOX.
Copy code
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
3 Views