1

I want to draw gradient line in jetpack compose. I tried some code but it was not correct as my expected.

Expected Output

enter image description here

Actual Output

enter image description here

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(),
                        )
                    }
            ) {}
        }
    }
}
Kotlin Learner
  • 3,995
  • 6
  • 47
  • 127

2 Answers2

3
Brush.verticalGradient(listOf(Color.Red, Color.Red))

Please try this.

J.K
  • 2,290
  • 1
  • 18
  • 29
2

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.

enter image description here

@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,
)

enter image description here

Thracian
  • 43,021
  • 16
  • 133
  • 222