I want to draw gradient line in jetpack compose. I tried some code but it was not correct as my expected.
Expected Output
Actual Output
Code
@Preview(showBackground = true)
@Composable
fun DrawTimeLine() {
Column(Modifier.fillMaxSize()) {
repeat(2) { index ->
val (height, brush) = if (index == 0) {
75.dp to Brush.linearGradient(listOf(Color.Blue, Color.Red))
} else {
25.dp to Brush.linearGradient(listOf(Color.Red, Color.Red))
}
Column(
modifier = Modifier
.fillMaxWidth()
.height(height)
.drawBehind {
drawLine(
brush = brush,
start = Offset(x = center.x, y = 0F),
end = Offset(x = center.x, y = size.height),
strokeWidth = 2.dp.toPx(),
)
}
) {}
}
}
}
Brush.linearGradient
creates a gradient with 45 degrees angle by default using start and end values. It's possible to change rotation angle , changing by 45 degrees is quite simple, rotating by other degrees require extending Brush i think, you can check out this answer for gradient angle rotation.
You can either change it by 90 degrees by setting start and end appropriately or use Brush.verticalGradient
which more is more convenient way to do it.
@Stable
fun verticalGradient(
vararg colorStops: Pair<Float, Color>,
startY: Float = 0f,
endY: Float = Float.POSITIVE_INFINITY,
tileMode: TileMode = TileMode.Clamp
): Brush = Brush.linearGradient(
*colorStops,
start = Offset(0.0f, startY),
end = Offset(0.0f, endY),
tileMode = tileMode
)
If you draw a line at any point using linear brush will see that you are drawing segments of rectangle gradient below because gradient is set based on start and end positions.
@Preview
@Composable
private fun GradientTest() {
val brush = Brush.linearGradient(listOf(Color.Blue, Color.Red))
Column(
modifier = Modifier.padding(20.dp)
) {
var positionX by remember {
mutableStateOf(0f)
}
Slider(
value = positionX,
onValueChange = {
positionX = it
},
valueRange = 0f..1000f
)
Box(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(1f)
.drawBehind {
drawRect(
brush = brush
)
}
)
Spacer(modifier = Modifier.height(20.dp))
Box(
modifier = Modifier
.fillMaxWidth(.5f)
.aspectRatio(1f)
.drawBehind {
drawLine(
brush = brush,
start = Offset(positionX, 0f),
end = Offset(positionX, size.height),
strokeWidth = 40f
)
}
)
}
}
AS J.K answered using Brush.verticalGradient
which equally proportions the color between the height of the composable. If you use color stops you can define which color should take which percentage
val verticalBrush = Brush.verticalGradient(
listOf(Color.Blue, Color.Red)
)
val verticalBrush2 = Brush.verticalGradient(
0.25f to Color.Blue,
1f to Color.Red,
)