TextView to Text

Text is the direct replacement of TextView. It includes all standard TextView customizations and many more. Customizations can be passed directly as parameters to the composable. You can extract all customizations into a TextStyle that you can use through your app. You can provide a TextStyle directly into a Text as a parameter or via theming.

Example of usage:

Text("hello from Compose") 

How to customize your text (text color, size, max lines, etc)

The Text composable supports functionality you would expect such as changing its textSize, setting its maxLines or its color.

In addition to standard TextView functionality, you get the option to modify the text's letterSpacing, lineHeight and more. All customization options can be found by inspecting the parameters of the Text composable.

Text(
    "Hello from Compose",
    fontSize = 18.sp,
    maxLines = 1,
    color = Color.Blue,
)

How to reuse your text styles

One of the most important parameters of Text composable is the style parameter. It allows you to pass a TextStyle. This works in a very similar way to Views's TextAppearance.

A TextStyle contains all customizations you can apply as parameters to a Text composable. The benefit is that you can reuse the created style in multiple Text composables in your app. This makes styling consistent across the app and makes your composables easier to read and maintain.

A typical TextStyle looks like this:

val h1 = TextStyle(
    fontFamily = FontFamily.Default,
    fontWeight = FontWeight.SemiBold,
    fontSize = 42.sp
)

which you can use in your Text like this:

Text("My big header", style = h1)

Alternatively, you can define the style in your application's theme like this:

val Typography = Typography(
    h1 = TextStyle(
        fontFamily = FontFamily.Default,
        fontWeight = FontWeight.SemiBold,
        fontSize = 42.sp
    )
)

@Composable
fun MyTheme(content: @Composable () -> Unit) {
    MaterialTheme(
        typography = Typography,
        content = content
    )
}

and use it in your composable:

MyTheme {
    Text("My big header", style = MaterialTheme.Typography.h1)
}

How to use custom Fonts

One of the parameters of Text is fontFamily. Compose provides some built-in fonts you can use that are device dependant, using the FontFamily object.

If the passed font family is not available on the device, a default font will be used instead. Alternatively, you can also define your own custom fonts in order to personalize your app further.

Example:

Text("This text is written in cursive", fontFamily = FontFamily.Cursive)

The font family can be used directly as a parameter to your Text composable or via a TextStyle. The TextStyle can be used in your application's theme.

There is a big chance that you will need to change the font of the entire app. For this purpose, you can use the defaultFontFamily parameter of the Typography class, which is part of the MaterialTheme.

How to create custom Fonts

First, store your .tff font files into your project under your res/font folder.

You can find a plethora of free to use fonts at Google Fonts.

Each font family might come with multiple files. Each file represents a different weight of the font, such as bold, semi-bold or thin. You will have to copy all those files in your resource folder.

Then, create a new FontFamily object and link each file to a respective styling:

val Urbanist = FontFamily(
    Font(R.font.urbanist_thin, weight = FontWeight.Thin),
    Font(R.font.urbanist_light, weight = FontWeight.Light),
    Font(R.font.urbanist_regular, weight = FontWeight.Normal),
    Font(R.font.urbanist_medium, weight = FontWeight.Medium),
    Font(R.font.urbanist_bold, weight = FontWeight.Bold),
    Font(R.font.urbanist_italic, style = FontStyle.Italic),
)

How to use strings from xml resources

You can continue using all your translated XML string resources in your composables. Instead of having to rely to a Resource or Context object, you can use the stringResource() function:

Text(stringResource(R.string.my_translated_string))

// stringResource accepts args too
Text(stringResource(R.string.hello_to), "Alex")

How to use string plurals from xml resources

There is currently no built-in way to use plurals. You would have to create your own function for the job.

You can use a mechanism called Composition Locals to get the current Context from a current composable function. This is what stringResource() and other similar resource functions use internally to get a hold of Context when needed.

A function for string plurals might look like this:

@Composable
fun quantityStringResource(
    @PluralsRes pluralResId: Int,
    quantity: Int,
    vararg formatArgs: Any? = emptyArray()
): String {
    return LocalContext.current.resources
        .getQuantityString(pluralResId, quantity, *formatArgs)
}

which you can use in your app like this:

// "Contact" or "Contacts" depending on the numberOfContacts
Text(quantityStringResource(R.plurals.contact), numberOfContacts)

// "No contact", "1 contact", or "$number contacts"
Text(
    quantityStringResource(R.plurals.x_number_of_contacts), 
    numberOfContacts, 
    numberOfContacts
)

How to make Text clickable

Instead of using a Modifier.clickable {} to make your text clickable, it is recommended to wrap your Text into an TextButton composable instead. The TextButton will style your Text according to your theme, and will include the right minimum touch target size required.

TextButton(onClick = { /*TODO start search*/ }) {
    Text("Search")
}

How to make part of Text clickable (UrlSpans)

Create an AnnotatedString with the styling and URL information you need:

val tag = "info"
val annotatedString = buildAnnotatedString {
    val text = "For more info click here"
    append(text)

    val start = text.indexOf("here")
    val end = start + 4

    addStyle(
        style = SpanStyle(
            color = MaterialTheme.colors.primary,
            textDecoration = TextDecoration.Underline
        ),
        start = start,
        end = end
    )

    addStringAnnotation(
        tag = tag,
        annotation = "https://viewtocomposable.com",
        start = start,
        end = end
    )
}

then pass the annotated String into a ClickableText and use the LocalUriHandler to launch the respective URL:

val uriHandler = LocalUriHandler.current
ClickableText(
    text = annotatedString,
    onClick = { offset ->
        annotatedString
            .getStringAnnotations(tag, offset, offset)
            .firstOrNull()
            ?.let { string ->
                uriHandler.openUri(string.item)
            }
    }
)

How to align my Text according to its baseline

Use Modifier.paddingFromBaseline() to place paddings to your composable according to your Text's first or last line's baseline.

Text(
    "Choose an account",
    modifier = Modifier.paddingFromBaseline(top = 40.dp),
    style = MaterialTheme.typography.h6
)
Previous ChapterUnderstanding Compose code
Next ChapterEditText to TextField