Johan Paul
Johan Paul

Reputation: 2466

Line with rounded edge on only one side in Compose?

I have a design for Android where I would need to draw a line with the rounded edge on only one side of the line.

Think a progress bar where both ends of the bar have rounded edges, but it consist of two colors and so that the intersecting part, where the colors change, should not have a rounded edge. My plan is to implement this by drawing two lines of correct length and color where each end has a rounded edge.

Is there some nice way to do it with Jetpack Compose?

I know I can make rounded edges in Compose like this:

drawLine(
     start = ..,
     end = ..,
     strokeWidth = 8.dp.toPx(),
     cap = StrokeCap.Round, 
)

But this will make both ends of the line rounded, right? Is there some nice way to only round one end of the line?

Edit: Sample picture: enter image description here

Upvotes: 0

Views: 1235

Answers (2)

Thracian
Thracian

Reputation: 67218

Progress bar with one rounded edge

enter image description here

@Preview
@Composable
fun Test2() {

Column {
    var progress by remember {
        mutableStateOf(0f)
    }

    Slider(value = progress, onValueChange = { progress = it })

    Canvas(
        modifier = Modifier
            .fillMaxSize()
            .graphicsLayer {
                compositingStrategy = CompositingStrategy.Offscreen
            }
    ) {

        val strokeWidth = 32.dp.toPx()
        val halfStrokeWidth = strokeWidth / 2f

        val width = size.width
        drawLine(
            color = Color.Gray,
            start = Offset(halfStrokeWidth, 100f),
            end = Offset(width - halfStrokeWidth, 100f),
            cap = StrokeCap.Round,
            strokeWidth = strokeWidth
        )

        drawLine(
            color = Color.Red,
            start = Offset(0f, 100f),
            end = Offset(width * (progress), 100f),
            strokeWidth = 32.dp.toPx(),
            blendMode = BlendMode.SrcIn
        )
    }
}

}

Drawing one side Rounded line

extension function of DrawScope that draws 2 lines.

 fun DrawScope.drawHorizontalOneEdgeLine(
    color: Color,
    start: Offset,
    end: Offset,
    strokeWidth: Float = Stroke.HairlineWidth,
    cap: StrokeCap = Stroke.DefaultCap,
    pathEffect: PathEffect? = null,
    alpha: Float = 1.0f,
    colorFilter: ColorFilter? = null,
    blendMode: BlendMode = DrawScope.DefaultBlendMode
) {
    drawLine(
        color = color,
        start = start,
        end = end,
        strokeWidth = strokeWidth,
        cap = cap,
        pathEffect = pathEffect,
        alpha = alpha,
        colorFilter = colorFilter,
        blendMode = blendMode
    )

    drawLine(
        color = color,
        start = start.plus(Offset(strokeWidth / 2f, 0f)),
        end = end,
        strokeWidth = strokeWidth,
        cap = StrokeCap.Square,
        pathEffect = pathEffect,
        alpha = alpha,
        colorFilter = colorFilter,
        blendMode = blendMode
    )
}

Result

enter image description here

Demo

@Preview
@Composable
fun LineSample() {

    Canvas(modifier = Modifier.fillMaxSize()) {
        drawLine(
            color = Color.Red,
            start = Offset(100f, 100f),
            end = Offset(700f, 100f),
            cap = StrokeCap.Round,
            strokeWidth = 32.dp.toPx()
        )

        drawHorizontalOneEdgeLine(
            color = Color.Blue,
            start = Offset(100f, 200f),
            end = Offset(700f, 200f),
            cap = StrokeCap.Round,
            strokeWidth = 32.dp.toPx()
        )


        drawLine(
            color = Color.LightGray,
            start = Offset(100f, 1000f),
            end = Offset(1000f, 1000f),
            cap = StrokeCap.Round,
            strokeWidth = 32.dp.toPx()
        )

        drawHorizontalOneEdgeLine(
            color = Color.Green,
            start = Offset(100f, 1000f),
            end = Offset(600f, 1000f),
            cap = StrokeCap.Round,
            strokeWidth = 32.dp.toPx()
        )
    }
}

Upvotes: 1

Jan Bína
Jan Bína

Reputation: 7278

You can do that with drawPath:

drawPath(
  path = Path().apply {
    addRoundRect(
      RoundRect(
        left = 0F,
        top = 0F,
        right = 200F,
        bottom = 8.dp.toPx(),
        topLeftCornerRadius = CornerRadius(4.dp.toPx(), 4.dp.toPx()),
        bottomLeftCornerRadius = CornerRadius(4.dp.toPx(), 4.dp.toPx()),
        topRightCornerRadius = CornerRadius.Zero,
        bottomRightCornerRadius = CornerRadius.Zero,
      )
    )
  }
)

Upvotes: 1

Related Questions