https://kotlinlang.org logo
#compose
Title
# compose
k

KotlinLeaner

02/14/2023, 10:14 PM
Hi guys, I am drawing progress bar in canvas. I did that with the help of amazing tutorials/examples in canvas. There is a problem in some part i.e. I want to add a transparent part after the Gradient color line end. I don't understand why this tiny vertical line comes and I didn't figure out properly.
Copy code
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
                    )
                }
            }
        }
    }
}
Trying to achieve this transparent part after gradient line ends
Actual output where vertical line come
r

romainguy

02/14/2023, 10:39 PM
instead of doing a drawLine + drawArc you could draw a line with a round cap
Alternatively you can close that gap by moving your arc by 1px to the left (or being more careful with rounding of that value)
k

KotlinLeaner

02/14/2023, 10:41 PM
Can you provide a example for draw a cap? I cannot find the way.. Thanks
r

romainguy

02/14/2023, 10:43 PM
You are doing it for your line with the gradient, using
cap = StrokeCap.Round
Just do the same for the white line
k

KotlinLeaner

02/14/2023, 10:45 PM
Ok I'll try now. I really appreciate it.
e

ephemient

02/14/2023, 10:54 PM
if you really want it transparent, allowing any background to show through, you might consider using clipPath
(or using paths to begin with)
but yeah, if it's a solid background that you can copy, that's easier
I suppose you could draw a "invisible" line with BlendMode.DstOut to "erase", but that might not do what you expect without CompositingStrategy.Offscreen
r

romainguy

02/14/2023, 11:08 PM
You would need a rasterized graphics layer for that to work
e

ephemient

02/14/2023, 11:10 PM
or you could punch a hole all the way through to the window background? 😄
(but that's what I thought Offscreen would do)
r

romainguy

02/14/2023, 11:14 PM
That would clear to black
11 Views