Jetpack Compose自定义进度条ProgressIndicator

「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战」

当不满足官方的ProgressIndicator的时候,作为一名优秀的安卓开发者,肯canvas绘图定要自定义一个啦

Jetpack Compose自定义进度条ProgressIndicator

自定义Progresscanvas什么意思Indicator

compose的Canvasandroid是什么系统提供了丰富的Api足以满足我们打造各种炫酷效果,我们只管发挥想象力,之前我有写过用Compose画太阳和月亮,感兴趣的可以去我的文章里面看。

传统写法Android自定义加载进度条+自定义Dialog简洁弹窗 – (juejin.cn)

首先用Canvandroid平板电脑价格as的drawLicanvas在线平面设计ne简单画一条直线

Canvas(modifier.padding(16.dp).fillMaxWidth()) {
        val canvasWidth = size.width  // 画布的宽
        val canvasHeight = size.height  // 画布的高
        drawLine(
            color = Color.Green,
            start = Offset(0f, 0f),
            end = Offset(canvasWidth, 0f),
            strokeWidth = 40f         
        )
    }

Jetpack Compose自定义进度条ProgressIndicator

用StrokeCap设置成圆角

cap = StrokeCap.Round

这绿太刺眼换一个

Jetpack Compose自定义进度条ProgressIndicator

接着传canvas可画官网值让它动起来
定义一个接收参数value的范围 0~100

那么进度条的宽度就是画布的总宽度 (value/100)

@Composable
private fun progressbar(modifier: Modifier = Modifier, value: Float) {
    Canvas(modifier.padding(16.dp).fillMaxWidth()) {
        val canvasWidth = size.width  // 画布的宽
        val canvasHeight = size.height  // 画布的高
        drawLine(
            color = Color.Cyan,
            start = Offset(0f, 0f),
            end = Offset(canvasWidth*(value/100), 0f),
            strokeWidth = 40f ,
            cap = StrokeCap.Round
        )
    }
}

使用-模拟传值

var progressValue by remember { mutableStateOf(0F) }
for (i in 1..100) { 
    progressValue = i.toFloat()
}
progressbar(value = progressValue)

不对呀,这太快看不清了呀,canvas英语那怎么办呢?
好办用delay()延迟一下

compose中使用携程就用到LaunchedEffect接着把for循环放到launch里面。因为delay()是个挂起函数

var progressValue by remember { mutableStateOf(0F) }
LaunchedEffect(rememberScaffoldState()) {
    for (i in 1..100) {
        delay(30)
        progressValue = i.toFloat()
    }
}
progressbar(value = progressValue)

Jetpack Compose自定义进度条ProgressIndicator

大致效果出来了继续优化

加个进度文本

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

裁剪时手抖了一下所以边缘略微闪烁

完整代码

@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  // 画布的宽
            val canvasHeight = size.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))
        }
    }
}

把进度条换成渐变色

这个android手机就要用到Path和drawPath了

完整代码

@Composable
private fun progressbar(modifier: Modifier = Modifier, value: Float) {
    Column() {
        Canvas(modifier.fillMaxWidth().padding(16.dp)) {
            val canvasWidth = size.width  // 画布的宽
            val canvasHeight = size.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))
        }
    }
}