Jetpack Compose 使用点圆绘制弧线

13
我想在Jetpack Compose的画布上绘制一个弧形,并在进度边缘上放置一个小圆圈,就像这张图片一样:enter image description here。我找到了如何使用弧形画布绘制进度条,但还不知道如何绘制圆圈以匹配弧线的边缘。这是我的进度代码:
@Composable
fun ComposeCircularProgressBar(
    modifier: Modifier = Modifier,
    percentage: Float,
    fillColor: Color,
    backgroundColor: Color,
    strokeWidth: Dp
) {
    Canvas(
        modifier = modifier
            .padding(strokeWidth / 2)
    ) {
        // Background Line
        drawArc(
            color = backgroundColor,
            135f,
            270f,
            false,
            style = Stroke(strokeWidth.toPx(), cap = StrokeCap.Butt)
        )
        // Fill Line
        drawArc(
            color = fillColor,
            135f,
            270f * percentage,
            false,
            style = Stroke(strokeWidth.toPx(), cap = StrokeCap.Round)
        )
    }
}

注意:目前我知道使用Canvas.drawCircle(offset = Offset)来绘制圆形,但是我还不知道如何计算Offset(x,y)以使其与进度边缘匹配。


1
这与compose无关,只是一个数学问题,例如参见此答案 - Phil Dukhov
1个回答

15

以下代码将根据提供的百分比生成带有圆形点的弧形。大部分都是正确的,只需通过解决数学方程找到圆上的点。

我假设圆的半径为小部件的高度/2

由于我们不绘制完整的圆,因此起始角度为140度,最大扫描角度为260度。(我通过试错法找到了这个值,以便它看起来与您的图像尽可能接近)

现在要绘制小白色圆,中心即所谓的偏移量必须位于(x,y),其中x和y由以下公式给出:

x = 半径 * sin (弧度角度) y = 半径 * cos (弧度角度)

@Composable
fun ComposeCircularProgressBar(
    modifier: Modifier = Modifier,
    percentage: Float,
    fillColor: Color,
    backgroundColor: Color,
    strokeWidth: Dp
) {
    Canvas(
        modifier = modifier
            .size(150.dp)
            .padding(10.dp)
    ) {
        // Background Line
        drawArc(
            color = backgroundColor,
            140f,
            260f,
            false,
            style = Stroke(strokeWidth.toPx(), cap = StrokeCap.Round),
            size = Size(size.width, size.height)
        )

        drawArc(
            color = fillColor,
            140f,
             percentage * 260f,
            false,
            style = Stroke(strokeWidth.toPx(), cap = StrokeCap.Round),
            size = Size(size.width, size.height)
        )


        var angleInDegrees = (percentage * 260.0) + 50.0
        var radius = (size.height / 2)
        var x = -(radius * sin(Math.toRadians(angleInDegrees))).toFloat() + (size.width / 2)
        var y = (radius * cos(Math.toRadians(angleInDegrees))).toFloat() + (size.height / 2)

        drawCircle(
            color = Color.White,
            radius = 5f,
            center = Offset(x,  y)
        )
    }
}

以下是我尝试的一些示例

80% 进度

@Preview
@Composable
fun PreviewPorgressBar() {
    ComposeCircularProgressBar(
        percentage = 0.80f,
        fillColor = Color(android.graphics.Color.parseColor("#4DB6AC")),
        backgroundColor = Color(android.graphics.Color.parseColor("#90A4AE")),
        strokeWidth = 10.dp
    )
}

45% progress

@Preview
@Composable
fun PreviewPorgressBar() {
    ComposeCircularProgressBar(
        percentage = 0.45f,
        fillColor = Color(android.graphics.Color.parseColor("#4DB6AC")),
        backgroundColor = Color(android.graphics.Color.parseColor("#90A4AE")),
        strokeWidth = 10.dp
    )
}

100% progress

@Preview
@Composable
fun PreviewPorgressBar() {
    ComposeCircularProgressBar(
        percentage = 1f,
        fillColor = Color(android.graphics.Color.parseColor("#4DB6AC")),
        backgroundColor = Color(android.graphics.Color.parseColor("#90A4AE")),
        strokeWidth = 10.dp
    )
}

[更新] 如果您对逐步教程感兴趣,可以在此处阅读: https://blog.droidchef.dev/custom-progress-with-jetpack-compose-tutorial/


你好!在圆形进度条上添加阴影是否可行? - captainhaddock
是的,您可以在圆形进度条上添加阴影。只需创建另一个弧(使用您喜欢的阴影颜色 - 例如,我会选择相同的灰色但不透明度为45%),然后将该弧向右偏移2 DP即可。就这样。 - droidchef
将这个转换成一个带有可拖动滑块的进度条有多难? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接