Search code examples
androidandroid-jetpackandroid-jetpack-composeandroid-jetpack-compose-text

How to create a text with multiple Font Styles?


I would like to have a text with multiple FontStyles on it.

Example (text mixing bold and italic):

This is my text!

Normally I could do that like this:

<string name="test"><![CDATA[This <b>is my</b> <i><text/i>]]></string>

How to do the same using Text and FontStyles in Compose?

Notes: I don't want to split my text in multiple entries in strings.xml file.


Solution

  • You can use withStyle() to apply the style. You typically need either SpanStyle or ParagraphStyle.

    The example below uses data class collection, which may include bold, italic or whatever is needed. In your case, you would need to build a collection with different styles. In the example below, I use bold style only.

    @Composable
    fun TextStyled() {
        Text(
            buildAnnotatedString {
                withStyle(style = ParagraphStyle(lineHeight = 32.sp)){
                    textData.forEach { sd ->
                        if (sd.bold) {
                            withStyle(style = SpanStyle(
                                fontSize = 22.sp,
                                fontWeight = FontWeight.Bold),
                            ) {
                                append(sd.text)
                            }
                        } else {
                            withStyle(style = SpanStyle(
                                fontSize = 22.sp,
                                fontWeight = FontWeight(300)
                            )) {
                                append(sd.text)
                            }
                        }
                    }
    
                }
            }
        )
    }
    

    Another solution is to use regex. Example below replaces all substrings text to Text() with FontWeight.Bold.

    @Composable
    fun TextStyled() {
        val text = "This is <b>my text</b> in bold, and this is <b>another text</b> in bold"
        val regex = "<b>(.*?)</b>".toRegex()
        val boldSubstrings = regex.findAll(text).map { it.groupValues[1] }.toList()
        val normalSubstrings = regex.split(text)
    
        Text(
            buildAnnotatedString {
                withStyle(style = SpanStyle(color = Color.DarkGray, fontSize = 16.sp)){
                    normalSubstrings.forEachIndexed { index, s ->
                        withStyle(style = SpanStyle(
                            fontSize = 16.sp,
                            color = Color.DarkGray
                        )
                        ){ append(s) }
    
                        if (index < boldSubstrings.size) {
                            withStyle(style = SpanStyle(
                                fontSize = 16.sp,
                                color = Color.DarkGray,
                                fontWeight = FontWeight.Bold
                            )
                            ){ append(boldSubstrings[index]) }
                        }
                    }
                }
            }
        )
    }
    

    You can find more information about text styling in the official Jetpack Compose documentation.