“This is the 14th day of my participation in the First Challenge 2022.

When the official ProgressIndicator is not satisfied, as a good Android developer you will definitely need to customize one

Custom ProgressIndicator

Compose’s Canvas provides a rich Api that allows us to create all kinds of cool effects. Let’s just use our imagination. I wrote about composing the sun and moon in the past.

Android custom loading progress bar + custom Dialog simple popover – juejin (cn)

Start by simply drawing a line using the Canvas drawLine

Canvas(modifier.padding(16.dp).fillMaxWidth()) {

        val canvasWidth = size.width  // Width of canvas
        val canvasHeight = size.height  // Canvas height

        drawLine(
            color = Color.Green,
            start = Offset(0f.0f),
            end = Offset(canvasWidth, 0f),
            strokeWidth = 40f)}Copy the code

Use StrokeCap to set rounded corners

cap = StrokeCap.Round
Copy the code

This green is too harsh. Change it

And then pass the value and make it move and define a range from 0 to 100 to receive the value

So the width of the progress bar is the total width of the canvas times value divided by 100.

@Composable
private fun progressbar(modifier: Modifier = Modifier, value: Float) {


    Canvas(modifier.padding(16.dp).fillMaxWidth()) {

        val canvasWidth = size.width  // Width of canvas
        val canvasHeight = size.height  // Canvas height

        drawLine(
            color = Color.Cyan,
            start = Offset(0f.0f),
            end = Offset(canvasWidth*(value/100), 0f),
            strokeWidth = 40f ,
            cap = StrokeCap.Round
        )

    }
}
Copy the code

Use – to simulate passing values

var progressValue by remember { mutableStateOf(0F)}for (i in 1.100.) { 
    progressValue = i.toFloat()
}
progressbar(value = progressValue)
Copy the code

Wrong ah, this is too fast to see clearly ah, that how to do? Let’s delay()

For compose, use Ctrip for LaunchedEffect and then put the for loop inside launch. Because delay() is a suspend function

var progressValue by remember { mutableStateOf(0F) }

LaunchedEffect(rememberScaffoldState()) {
    for (i in 1.100.) {
        delay(30)
        progressValue = i.toFloat()
    }
}
progressbar(value = progressValue)
Copy the code

The general effect is out and continue to optimize

Add a progress text

Column() {

    Canvas(modifier.fillMaxWidth().padding(16.dp)) {
      ...
    }
    Row {
        Spacer(Modifier.weight(1f))
        Text("$value%",modifier.padding(end =16.dp))
    }

}
Copy the code

The edge glints a little bit because of the hand shaking

The complete code

@Composable
private fun progressbar(modifier: Modifier = Modifier, value: Float) {

   val color = Brush.verticalGradient(
        listOf(
            CustomTheme.colors.statusBarColor,
            CustomTheme.colors.background
        )
    )
    Column() {

        Canvas(modifier.fillMaxWidth().padding(16.dp)) {

            val canvasWidth = size.width  // Width of canvas
            val canvasHeight = size.height  // Canvas height

            drawLine(
                color = Color.Cyan,
                start = Offset(0f.0f),
                end = Offset(canvasWidth*(value/100), 0f),
                strokeWidth = 40f ,
                cap = StrokeCap.Round
            )
        }
        Row {
            Spacer(Modifier.weight(1f))
            Text("$value%",modifier.padding(end =16.dp))
        }

    }

}
Copy the code

Change the progress bar to gradient

So this is going to use Path and drawPath

The complete code

@Composable
private fun progressbar(modifier: Modifier = Modifier, value: Float) {

    Column() {

        Canvas(modifier.fillMaxWidth().padding(16.dp)) {

            val canvasWidth = size.width  // Width of canvas
            val canvasHeight = size.height  // Canvas height
            val strokeWidth = canvasHeight / 20
            val path = Path()
            path.lineTo(canvasWidth*(value/100), 0f)

            drawPath(
                path = path,
                style = Stroke(
                    width = strokeWidth,
                    cap = StrokeCap.Round
                ),
                brush = Brush.horizontalGradient(
                    colors = listOf(
                        Color.Transparent,
                        Color.Cyan
                    )
                )

            )
        }
        Row {
            Spacer(Modifier.weight(1f))
            Text("$value%",modifier.padding(end =16.dp))
        }

    }

}
Copy the code