Search code examples
textandroid-jetpack-composedraw

Compose draw text with border and gradient


Is there any way to draw text like that in compose which will have border and shadow like drop. Font does not matter.

Text to be drawn

I have tried AnnotatedString to apply the same gradient to each letter with this code:

        val colorStops = arrayOf(
            0.0f to Color(0xffe2e145),
            0.2f to Color(0xff7ab624)
        )
            Text(
                text = buildAnnotatedString {
                    for (letter in "ANIMALS".toCharArray()) {
                        withStyle(
                            SpanStyle(
                                brush = Brush.linearGradient(colorStops = colorStops)
                            )
                        ) {
                            append(letter)
                        }
                    }
                },
                fontSize = 60.sp
            )

but it just gets parsed wrong and only gets applied to first letter only

Text which is actually drawn

Do you know what I could be doing wrong or is there a better way to do this? One more thing would like text to be replacable.

If anyone has any ideas would be very grateful.

Edit

This is how stroke looks like on my Galaxy S10

Incorrect stroke


Solution

  • You can use a Box to put more Text elements on top of another:

    val colorStops = listOf(
        Color(0xffe2e145),
        Color(0xff7ab624)
    )
    
    Box(
        modifier = Modifier
            .fillMaxWidth()
    ) {
    
        //Filled Text
        Text(
            text = longText,
            color = Color(0xffe2e145),
            fontSize = 64.sp
        )
    
        //Shadow text with a gradient color.
        Text(
            text = longText,
            modifier = Modifier.offset(2.dp, 3.dp),
            style = TextStyle(
                brush = Brush.horizontalGradient(
                    colors = colorStops,
                    tileMode = TileMode.Mirror
                )
            ),
            fontSize = 64.sp
        )
    
        //Text with stroke border
        Text(
            text = longText,
            color = Color(0xffB71C1C),
            style = TextStyle.Default.copy(
                fontSize = 64.sp,
                drawStyle = Stroke(
                    miter = 10f,
                    width = 2f,
                    join = StrokeJoin.Round
                )
            )
        )
     }
    

    enter image description here

    Another option is to apply a shadow and a brush to the Text:

    Box(
        modifier = Modifier
            .fillMaxWidth()
    ) {
    
        //Shadow and Brush Text
        Text(
            text = longText,
            style = TextStyle(
                shadow = Shadow(
                    offset = Offset(8f, 8f),
                    blurRadius = 6f,
                    color = LightGray
                ),
                brush = Brush.horizontalGradient(
                    colors = colorStops,
                    tileMode = TileMode.Mirror
                )
            ),
            fontSize = 64.sp
        )
    
        //Text with stroke border
        Text(
            text = longText,
            color = Color(0xffB71C1C),
            style = TextStyle.Default.copy(
                fontSize = 64.sp,
                drawStyle = Stroke(
                    miter = 10f,
                    width = 2f,
                    join = StrokeJoin.Round
                )
            )
        )
    }
    

    enter image description here