Reputation: 2466
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?
Upvotes: 0
Views: 1235
Reputation: 67218
@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
)
}
}
}
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
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
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