Я хочу нарисовать прозрачную дугу после окончания радиуса цветового градиента. Звучит запутанно. У меня есть индикатор выполнения, в котором я заканчиваю строку в позиции X
. После этого я хочу показать прозрачное дуговое пространство в позиции X
с помощью линейного градиента. Я пытаюсь использовать drawArc
, но это работает неправильно.
@Composable
fun DrawProgressBar() {
val activity = LocalContext.current as AppCompatActivity
val rangeComposition = RangeComposition()
val itemLst = rangeComposition.bpExplained
val boxSize = 30.dp
val brush = Brush.horizontalGradient(listOf(Color.Red, Color.Blue))
val progressBarPointer = rangeComposition.findReadingWithPointer(142, 90).second
Box(
modifier = Modifier
.background(Color.White)
.height(height = boxSize)
) {
Canvas(
modifier = Modifier.fillMaxSize()
) {
val strokeWidth = 8.dp
val canvasWidth = size.width
val canvasHeight = size.height
val strokeWidthPx = density.run { strokeWidth.toPx() }
drawLine(
start = Offset(x = 0f, y = canvasHeight / 2),
end = Offset(x = canvasWidth, y = canvasHeight / 2),
color = Color.Gray,
strokeWidth = strokeWidthPx,
cap = StrokeCap.Round,
)
val progressBarPointerInPixel = (progressBarPointer / 100f) * canvasWidth
activity.logE("progressBarPointerInPixel $progressBarPointerInPixel")
drawLine(
brush = brush,
start = Offset(x = 0f, y = canvasHeight / 2),
end = Offset(x = progressBarPointerInPixel, y = canvasHeight / 2),
strokeWidth = strokeWidthPx,
cap = StrokeCap.Round,
)
drawArc(
topLeft = Offset(x = progressBarPointerInPixel, y = canvasHeight / 2),
size = Size(8.dp.toPx(), strokeWidthPx),
color = Color.Cyan,
startAngle = -90f,
sweepAngle = 180f,
useCenter = true
)
itemLst.forEachIndexed { index, rangeItem ->
val endPointInPixel = (rangeItem.endPoint / 100f) * canvasWidth
if (index != itemLst.lastIndex) {
drawLine(
start = Offset(x = endPointInPixel, y = 0F),
end = Offset(x = endPointInPixel, y = boxSize.toPx()),
color = Color.Black,
strokeWidth = 4.dp.toPx(),
)
}
}
}
}
}
Фактический результат
Ожидаемый результат
Вы можете найти исходный код RangeComposition.kt.
ОБНОВЛЯТЬ
После того, как @GabrieleMariotti упомянул код, который я попробовал с белым цветом, и я вижу, что есть белая крошечная вертикальная полоса.
fun DrawProgressBar() {
val activity = LocalContext.current as AppCompatActivity
val rangeComposition = RangeComposition()
val itemLst = rangeComposition.bpExplained
val boxSize = 30.dp
val brush = Brush.horizontalGradient(listOf(Color.Red, Color.Blue))
val progressBarPointer = rangeComposition.findReadingWithPointer(142, 90).second
Box(
modifier = Modifier
.background(Color.White)
.height(height = boxSize)
) {
Canvas(
modifier = Modifier.fillMaxSize()
) {
val strokeWidth = 8.dp
val canvasWidth = size.width
val canvasHeight = size.height
val strokeWidthPx = density.run { strokeWidth.toPx() }
val pathEffect = PathEffect.dashPathEffect(floatArrayOf(canvasHeight / 19, canvasHeight / 19), 0f)
drawLine(
start = Offset(x = 0f, y = canvasHeight / 2),
end = Offset(x = canvasWidth, y = canvasHeight / 2),
color = Color.Gray,
strokeWidth = strokeWidthPx,
cap = StrokeCap.Round,
)
val progressBarPointerInPixel = (progressBarPointer / 100f) * canvasWidth
drawLine(
color = Color.White,
start = Offset(x = progressBarPointerInPixel, y = canvasHeight / 2),
end = Offset(x = progressBarPointerInPixel + strokeWidthPx / 2, y = canvasHeight / 2),
strokeWidth = strokeWidthPx,
)
drawLine(
brush = brush,
start = Offset(x = 0f, y = canvasHeight / 2),
end = Offset(x = progressBarPointerInPixel, y = canvasHeight / 2),
strokeWidth = strokeWidthPx,
cap = StrokeCap.Round,
)
drawArc(
topLeft = Offset(x = progressBarPointerInPixel, y = canvasHeight / 2 - strokeWidthPx / 2),
size = Size(strokeWidthPx, strokeWidthPx),
color = Color.White,
startAngle = -90f,
sweepAngle = 180f,
useCenter = true
)
itemLst.forEachIndexed { index, rangeItem ->
val endPointInPixel = (rangeItem.endPoint / 100f) * canvasWidth
if (index != itemLst.lastIndex) {
drawLine(
start = Offset(x = endPointInPixel, y = 0F),
end = Offset(x = endPointInPixel, y = boxSize.toPx()),
color = Color.Black,
strokeWidth = 1.2.dp.toPx(),
pathEffect = pathEffect
)
}
}
}
}
}
Результат
В вашей дуге вы должны изменить смещение topLeft
, учитывая также смещение высоты из-за strokeWidthPx
. Что-то вроде:
topLeft = Offset(x = progressBarPointerInPixel, y = canvasHeight / 2 - strokeWidthPx/2),
Также вы должны добавить линию от progressBarPointerInPixel
до progressBarPointerInPixel + strokeWidthPx/2
из-за закругленных углов.
Что-то вроде:
drawLine(
//gray line
)
drawLine(
color = Color.Cyan,
start = Offset(x = progressBarPointerInPixel , y = canvasHeight / 2),
end = Offset(x = progressBarPointerInPixel + strokeWidthPx/2, y = canvasHeight / 2),
strokeWidth = strokeWidthPx,
)
drawLine(
brush = brush,
start = Offset(x = 0f, y = canvasHeight / 2),
end = Offset(x = progressBarPointerInPixel, y = canvasHeight / 2),
strokeWidth = strokeWidthPx,
cap = StrokeCap.Round,
)
drawArc(
topLeft = Offset(x = progressBarPointerInPixel, y = canvasHeight / 2 - strokeWidthPx/2),
size = Size(strokeWidthPx,strokeWidthPx),
color = Color.Cyan,
startAngle = -90f,
sweepAngle = 180f,
useCenter = true
)
Чтобы получить прозрачную дугу, вы можете добавить blendMode = BlendMode.DstOut
к линии + дуге. Также требуется применить alpha !=1F
к Canvas
с помощью graphicsLayer(alpha = 0.99f)
Проверьте документ для получения более подробной информации о blendMode.
Canvas(
modifier = Modifier.fillMaxSize().graphicsLayer(alpha = 0.99f)
) {
drawLine(
//gray line
)
drawLine(
//...
color = Color.Cyan,
blendMode = BlendMode.DstOut
)
drawLine(
//gradient
)
drawArc(
blendMode = BlendMode.DstOut
)
}
@VivekModi Здесь довольно сложно добиться прозрачного раздела. Вам действительно нужна прозрачная дуга или вам достаточно дуги с тем же цветом фона вокруг бара?
Я думаю, фона вокруг машины будет достаточно, и он работает как положено. Я поставил arc
белого цвета и получил очень тонкую прямую вертикальную линию. Можем ли мы удалить это?
Я добавил белый цвет в arc
и добавил код в раздел ОБНОВЛЕНИЕ.
Я должен понять, почему эта тонкая граница из-за серой линии
Пожалуйста, дайте мне знать, если вы найдете правильный способ решения проблемы.
@VivekModi добавил код для создания прозрачного раздела. Я должен понять, почему существует тонкая граница.
Без проблем. @GabrieleMariotti благодарит миллион за поддержку. Пожалуйста, дайте мне знать, если вы найдете что-то.
ваш код добавляет
arc
после строки. Но мы добавляем Прозрачный цвет, он показывает меня за серым цветом. это отдельный вопрос, я должен открыть для этого?