You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose 如何在Canvas绘制带斜纹图案的线性进度条

方案实现

推荐方案:纯代码生成斜纹填充(无需额外资源,全Compose实现)

你原本的drawLine方法不需要大改,只需要将传入的color参数替换为brush参数,通过自定义Shader生成斜纹效果即可,不需要依赖任何XML资源或者drawable文件。
首先实现斜纹Brush的生成方法:

fun createDiagonalStripeBrush(
    stripeColor: Color,
    gapColor: Color = Color.White,
    stripeWidth: Dp = 4.dp,
    gapWidth: Dp = 3.dp,
    angle: Float = 45f
): Brush {
    // 兼容API 33以下的备用实现如果不需要兼容可以直接用Runtime Shader
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        ShaderBrush(
            object : Shader() {
                override fun execute(inputs: ShaderInputs, size: FloatSize): ShaderResult {
                    val totalTileWidth = (stripeWidth + gapWidth).toPx()
                    val radians = Math.toRadians(angle.toDouble()).toFloat()
                    val cos = cos(radians)
                    val sin = sin(radians)
                    return ShaderResult { x, y, _ ->
                        val projectedPos = x * cos + y * sin
                        if (projectedPos % totalTileWidth < stripeWidth.toPx()) {
                            stripeColor
                        } else {
                            gapColor
                        }
                    }
                }
            }
        )
    } else {
        // 低版本兼容实现:通过绘制重复条纹生成Bitmap再平铺
        val tileSizePx = (stripeWidth + gapWidth).toPx().toInt() * 4
        val bitmap = ImageBitmap(tileSizePx, tileSizePx)
        val canvas = Canvas(bitmap)
        val paint = Paint().apply { color = stripeColor }
        val radians = Math.toRadians(angle.toDouble()).toFloat()
        val offsetStep = (stripeWidth + gapWidth).toPx()
        var currentOffset = -tileSizePx.toFloat()
        while (currentOffset < tileSizePx * 2) {
            canvas.save()
            canvas.rotate(angle, tileSizePx / 2f, tileSizePx / 2f)
            canvas.drawRect(
                x = currentOffset,
                y = 0f,
                width = stripeWidth.toPx(),
                height = tileSizePx.toFloat(),
                paint = paint
            )
            canvas.restore()
            currentOffset += offsetStep
        }
        ImageBrush(
            imageBitmap = bitmap,
            tileModeX = TileMode.Repeated,
            tileModeY = TileMode.Repeated
        )
    }
}

然后修改你原有的绘制代码即可:

// 按需调整参数匹配设计稿
val stripeProgressBrush = createDiagonalStripeBrush(
    stripeColor = progressColor,
    gapColor = Color.White,
    stripeWidth = 3.dp,
    gapWidth = 2.dp,
    angle = -45f
)

drawLine(
    brush = stripeProgressBrush, // 替换原有的color参数
    start = Offset(if (whiteGap) progressCapWidth else startOffsetBg, yOffset),
    end = Offset(endOffsetProgress, yOffset),
    strokeWidth = progressHeight.toPx(),
    cap = if (roundedCorners) StrokeCap.Round else StrokeCap.Butt,
)

可选方案:使用drawable平铺

如果已经有现成的斜纹drawable资源,也可以直接转成平铺Brush使用,不需要XML布局:

val context = LocalContext.current
val stripeDrawable = ContextCompat.getDrawable(context, R.drawable.your_stripe_res)!!
val stripeBitmap = stripeDrawable.toBitmap().asImageBitmap()
val tiledBrush = ImageBrush(
    imageBitmap = stripeBitmap,
    tileModeX = TileMode.Repeated,
    tileModeY = TileMode.Repeated
)

// 同样传入drawLine的brush参数即可
drawLine(
    brush = tiledBrush,
    // 其余参数保持原有逻辑不变
)

该方案需要适配不同屏幕密度的drawable资源,灵活度低于纯代码生成方案,优先推荐第一种实现。

内容的提问来源于stack exchange,提问作者daniel-eh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 09:45:04