нарисовать закругленные углы на холсте с помощью drawArc
Я пытаюсь создать круговую диаграмму в Jetpack Compose. Я пытаюсь скруглить углы для каждого круга на диаграмме. Но у меня проблемы с поворотами по углам. Я попробовал использоватьcap = StrokeCap.Round
вdrawArc
в холсте, но мне не удалось скруглить только углы.
Это то, что у меня есть на данный момент, и результат выглядит следующим образом. Как видите, углы каждого пирога имеют прямоугольную форму. Есть ли способ сделать их круглыми?
@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()
}
}
Я пытаюсь сделать так, чтобы дуга выглядела вот так
2 ответа
Проблема заключается в том, как вы структурируете зазор между дугами, поэтому вы не видите закругленных краев приStrokeCap.Round
. Вам нужно сделать это как
startAngle = startAngle + gap,
и SweepAngle как
sweepAngle = sweepAngle - gap * 2,
и когда у тебя будет достаточно пробелов в раунде
@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
}
}
}
}
Я подробно объяснил логику в этом ответе
/questions/65146552/jetpack-sostavlyaet-canvas-arch-extra-stroke/65967656#65967656
Я нашел обходной путь, нарисовав две дуги, одну с
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 and 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
}
}
}
}