Lorenzo Benevento
Lorenzo Benevento

Reputation: 618

Applying cap on only one end of a stroked line in Android

Is it possible to apply a cap to only one of the two ends of a stroke while drawing in a Compose Canvas DrawScope context?

Upvotes: 2

Views: 1308

Answers (1)

Phil Dukhov
Phil Dukhov

Reputation: 87794

There is no built-in solution.

I could not find a solution for android.graphics.Canvas either: if you know how to do it in plain android canvas, you can use it in compose c with drawIntoCanvas.

The only approach I can think of is to draw the caps on top:

fun DrawScope.drawLine(
    color: Color,
    start: Offset,
    end: Offset,
    strokeWidth: Float = Stroke.HairlineWidth,
    startCap: StrokeCap,
    endCap: StrokeCap,
) {
    drawLine(
        color = color,
        start = start,
        end = end,
        strokeWidth = strokeWidth,
        cap = StrokeCap.Butt,
    )
    listOf(
        Triple(start, end, startCap),
        Triple(end, start, endCap),
    ).forEach {
        drawCap(
            color = color,
            start = it.first,
            end = it.second,
            strokeWidth = strokeWidth,
            cap = it.third
        )
    }
}

private fun DrawScope.drawCap(
    color: Color,
    start: Offset,
    end: Offset,
    strokeWidth: Float = Stroke.HairlineWidth,
    cap: StrokeCap,
) {
    when (cap) {
        StrokeCap.Butt -> Unit
        StrokeCap.Round -> {
            drawCircle(color, center = start, radius = strokeWidth / 2)
        }
        StrokeCap.Square -> {
            val offset = Offset(strokeWidth / 2, strokeWidth / 2)
            val size = Size(strokeWidth, strokeWidth)

            rotateRad(
                radians = (end - start).run { atan2(x, y) },
                pivot = start
            ) {
                drawRect(color, topLeft = start - offset, size = size)
            }
        }
    }
}

Calculating angle in case for a line in StrokeCap.Square is pretty simple, but if you need this for curves the solution may not be that easy.

But in you only need to support StrokeCap.Round knowing the start/end points and stroke width will be enough.

Upvotes: 2

Related Questions