Search code examples
androidkotlinandroid-jetpack-composeandroid-jetpackandroid-jetpack-compose-canvas

Gradient Line color in jetpack compose


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(),
                        )
                    }
            ) {}
        }
    }
}

Solution

  • 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