使用drawArc在画布上绘制圆角。

3
我正在尝试在Jetpack Compose中创建一个饼图。我想让每个饼图的角变圆。但是,我在使角变圆方面遇到了问题。我尝试在画布的drawArc中使用cap = StrokeCap.Round,但是没有成功使角变圆。
这是我目前的情况,结果看起来像这样。正如你所见,每个饼图的角都是矩形的。有没有办法使它们变圆?

enter image description here

@Composable
fun Chart() {
    Canvas(
        modifier = Modifier
            .fillMaxWidth()
            .aspectRatio(1f)
    ) {
        drawIntoCanvas {
            val width = size.width
            val radius = width / 2f
            val strokeWidth = radius * .3f
            var startAngle = 0f

            val items = listOf(25f, 25f, 25f, 25f, 25f, 25f, 25f, 25f)

            items.forEach {
                val sweepAngle = it.toAngle

                drawArc(
                    color = Color.Gray,
                    startAngle = startAngle,
                    sweepAngle = sweepAngle - 5,
                    useCenter = false,
                    topLeft = Offset(strokeWidth / 2, strokeWidth / 2),
                    size = Size(width - strokeWidth, width - strokeWidth),
                    style = Stroke(strokeWidth)
                )

                startAngle += sweepAngle
            }
        }
    }
}

private val Float.toAngle: Float
    get() = this * 180 / 100

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    MyApplicationTheme {
        Chart()
    }
}

我正在努力让弧线看起来像这样

enter image description here

2个回答

1
问题在于你如何构造弧之间的间隙,这就是为什么你看不到使用StrokeCap.Round时的圆角。你需要这样做:
startAngle = startAngle + gap,

和sweepAngle作为

sweepAngle = sweepAngle - gap * 2,

当你有足够的间隙时

enter image description here

@Composable
fun Chart() {
    Canvas(
        modifier = Modifier
            .fillMaxWidth()
            .aspectRatio(1f)
    ) {
        drawIntoCanvas {
            val width = size.width
            val radius = width / 2f
            val strokeWidth = radius * .3f
            var startAngle = 0f

            val items = listOf(25f, 25f, 25f, 25f, 25f, 25f, 25f, 25f)

            items.forEach {
                val sweepAngle = it.toAngle
                val gap = 25f/2

                drawArc(
                    color = Color.Gray,
                    startAngle = startAngle + gap,
                    sweepAngle = sweepAngle - gap * 2,
                    useCenter = false,
                    topLeft = Offset(strokeWidth / 2, strokeWidth / 2),
                    size = Size(width - strokeWidth, width - strokeWidth),
                    style = Stroke(strokeWidth, cap = StrokeCap.Round)
                )

                startAngle += sweepAngle
            }
        }
    }
}

我在这个答案中详细解释了背后的逻辑。

https://dev59.com/u9dzpIgBRmDukGFE2MKP#76135243


使用StrokeCap.Round时,它会从中心开始进行圆角处理。我只想要对弧线的角落进行圆角处理。 - Abp
使用StrokeCap.Round时,它会从中心开始进行圆角处理。我只想要对弧线的角落进行圆角处理。 - Abp
我在问题中添加了一张图片作为参考。 - Abp
我在问题中添加了一张图片作为参考。 - Abp
我在问题中添加了一张图片作为参考。 - undefined

1
我找到了一个解决办法,通过绘制两个弧线,一个使用style = Fill,另一个使用style = Stroke。希望这对某人有所帮助。
另一种方法是使用复杂的三角函数来完成,而不使用描边。这包括在极坐标和直角坐标之间进行转换。
使用这些公式和给定的外半径、内半径和角度,您可以计算出弧线的所有4个角落。
x1 = r1 cos ()
y1 = r1 sin ()
x2 = r2 cos ()
y3 = r2 sin ()
where radius = r1 = outerRadius, r2 = innerRadius and  = Math.toRadians(sweepAngle)

使用上述的数学方法,你应该能够找到一个弧线的 x 和 y 坐标点。 然后利用 Path,你可以绘制出来。
Path().apply{
   moveTo(x, y) // start of arc in top left - rounded edge
   arcTo(Rect(..), startAngle, sweepAngle, false) // or you can use `quadTo` or `curveTo` but you'll have to find control points
   quadTo(..) // to draw the rounded corner - top right
   lineTo(..) // line to next point - bottom right
   quadTo(..) // draw rounded corner in bottom right
   arcTo() // inner arc to bottom left corner - rounded edge
   quadTo() // bottom left corner
   lineTo() // line to top left corner
   quadTo() // top left corner
   close()
}

// 带有笔画的示例..
@Composable
fun Chart() {
    Canvas(
        modifier = Modifier
            .fillMaxWidth()
            .aspectRatio(1f)
    ) {
        drawIntoCanvas {
            val width = size.width
            val radius = width / 2f
            val innerRadius = radius - 40f
         
            var startAngle = 0f
            val center = Offset(size.width / 2f, size.height / 2f)

            val items = listOf(25f, 25f, 25f, 25f, 25f, 25f, 25f, 25f)

            items.forEach {
                val sweepAngle = it.toAngle

                val path = Path().apply{
                   drawArc(
                      Rect(
                        center.x - radius,
                        center.y - radius,
                        center.x + radius,
                        center.y + radius
                      ),
                      startAngle, 
                      sweepAngle,
                      false
                   )
                    drawArc(
                      Rect(
                        center.x - innerRadius,
                        center.y - innerRadius,
                        center.x + innerRadius,
                        center.y + innerRadius
                      ),
                      startAngle + sweepAngle, 
                      -sweepAngle,
                      false
                   )
                }
                
                drawPath(path, Color.Red, style = Fill)
                drawPath(path, Color.Red, style = Stroke(30f, StrokeCap.Round, StrokeJoin.Round))

                startAngle += sweepAngle
            }
        }
    }
}

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