Text

We know that Android uses TextView to display text, such as:

<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" // text content android:gravity="center" // text content center display android:textColor="#030" // textColor android:textSize="40sp" // textSize Android: textStyle = "bold | italic" / / writing style Bold and italic... />Copy the code

The display effect is shown as follows:

So how does Compose display text? In fact, we should have seen it clearly in the previous example, let’s look at it again:

@Composable fun Greeting(name: String, isShowName: Boolean) {val showName = if (isShowName) "display name" else "display name" Text(Text = "Hello $name! $showName") }Copy the code

For example, Compose and Android View can share the same string resource. For example, Compose and Android View can share the same string resource:

@Composable fun Greeting(isShowName: Boolean) {val showName = if (isShowName) "display name" else "Do not display name" Text(Text = "Hello ${stringResource(id =) R.string.compose_coder)}! $showName") } @Preview(showBackground = true, widthDp = 150, heightDp = 100) @Composable fun DefaultPreview() { ComposeTheme { Greeting(true) } }Copy the code

Using stringResource in Compose lets you read the stringResource directly and see it in Preview:

If we don’t need to do any other Settings, we can use the above Text to display the Text content, but the actual development is certainly not enough, let’s look at the source Text, there are some attributes:

@composable fun Text(Text: String, modifier: modifier = modifier, // modifier color: Composable fun Text(Text: String, modifier: modifier = modifier, // Unspecified, // The text Color fontSize: TextUnit = TextUnit.Unspecified, // The size fontStyle: fontStyle? = null, // font style fontWeight: fontWeight? = null, // fontFamily: fontFamily? Unspecified = null, // letterSpacing: TextUnit = TextUnit.Unspecified, // Character spacing textDecoration: textDecoration? TextAlign: textAlign? Unspecified, // lineHeight: TextUnit = TextUnit.Unspecified, // lineHeight: TextOverflow = textoverflow. Clip, // Visual overflow how to handle softWrap: Boolean = true, // Whether text should be broken at newlines maxLines: Int = Int.MAX_VALUE, // Max lines onTextLayout: (TextLayoutResult) -> Unit = {}, // Calculate new text layout callback style: TextStyle = localtextstyle.current // TextStyle (color, font, etc.) {// omit... }Copy the code

You can see that a lot of the parameters in Text, basically, have default values, and most of the parameters we’ve seen before, and we’ll show you all of these properties later.

Setting text Styles

Let’s set the text color first. Let’s override the Greeting method with no parameters

@Composable
fun Greeting() {
    Text(
        text = stringResource(R.string.compose_coder),
        color = Color.Red
    )
}
Copy the code

Let’s make the text red so you can see the preview.

Type size

The fontSize parameter is TextUnit. We are using int. sp to set the size, which is Compose’s extension function for us

@Stable
val Int.sp: TextUnit get() = pack(UNIT_TYPE_SP, this.toFloat())
Copy the code

Int, Float, Double can all be used this way, that is, the parameter type is TextUnit and we can set it this way.

italics

Let’s italicize the Text above:

We set italics with the FontStyle class.

inline class FontStyle(val value: Int) { override fun toString(): String { return when (this) { Normal -> "Normal" Italic -> "Italic" else -> "Invalid" } } companion object { /** Use the  upright glyphs */ val Normal = FontStyle(0) /** Use glyphs designed for slanting */ val Italic = FontStyle(1) /** Returns a list of possible values of [FontStyle]. */ fun values(): List<FontStyle> = listOf(Normal, Italic) } }Copy the code

The code is simple, with only two arguments, Normal and Italic.

The font size

We use FontWeight to set the font size.

@Immutable class FontWeight(val weight: Int) : Comparable<FontWeight> { companion object { /** [Thin] */ @Stable val W100 = FontWeight(100) /** [ExtraLight] */ @Stable  val W200 = FontWeight(200) /** [Light] */ @Stable val W300 = FontWeight(300) /** [Normal] / regular / plain */ @Stable val W400 = FontWeight(400) /** [Medium] */ @Stable val W500 = FontWeight(500) /** [SemiBold] */ @Stable val W600 = FontWeight(600) // omit...Copy the code

We can see that the FontWeight class takes an Int to indicate the size of the font, and Compose defines some common font size in its companion object for our convenience, such as Bold. Let’s set it up and see what it looks like.

FontWeight can not only be set to its own weight, we can use a custom value such as:

The font

Let’s use the fontFamily class.

@Immutable // TODO Unused parameter canLoadSynchronously sealed class FontFamily(val canLoadSynchronously: Boolean) {companion object {/** * Default font */ val Default: SystemFontFamily = DefaultFontFamily() /** * font with low contrast and flat stroke endings */ val SansSerif = GenericFontFamily("sans-serif") /** * Formal text for Scripts */ val Serif = GenericFontFamily(" Serif ") /** * fonts with the same fixed width */ val Monospace = GenericFontFamily("monospace") /** * Cursive */ val Cursive = GenericFontFamily(" Cursive ")}}Copy the code

The system provides the default 5 fonts above. I annotated them. Let’s see the differences between them.

We can add custom fonts and fonts as Android does, and put the corresponding font files in the res/font directory:

Once placed, you need to define fontFamily according to the font file:

Between characters

We want to set the spacing between characters in the Text using the letterSpacing parameter of Text. The letterSpacing parameter is TextUnit, so we just use “.sp” to set letterSpacing.

Text decoration

TextDecoration class to set the decoration, underline, underline, etc., let’s have a look at its source:

@Immutable class TextDecoration internal constructor(val mask: Int) { companion object { @Stable val None: TextDecoration = TextDecoration(0x0) /** * Underline */ @stable Val Underline: TextDecoration = TextDecoration(0x1) /** * middle line */ @stable val LineThrough: TextDecoration = TextDecoration(0x2) // omitted... }Copy the code

TextDecoration (FontFamily, fontWeight); TextDecoration (FontFamily, fontWeight);

Text alignment

Use the textAlign parameter to set the alignment of the text. By default, Text chooses natural Text alignment based on its content; Left-edge alignment is the default for left-to-right text; But for right-to-left Text, such as Arabic or Hebrew, the Text container will align the right edge. Take a look at the source code:

@Suppress("INLINE_CLASS_DEPRECATED") inline class TextAlign internal constructor(internal val value: Int) { override fun toString(): String { return when (this) { Left -> "Left" Right -> "Right" Center -> "Center" Justify -> "Justify" Start -> "Start" End -> "End" else -> "Invalid"}} Companion object {/** Left aligned */ val Left = TextAlign(1) /** Right aligned */ val Right = TextAlign(2) /** Center alignment */ val Center = TextAlign(3) /** * Content is aligned at both ends in the container */ val Justify = TextAlign(4) /** * Aligns text with the front edge of the container */ val Start = TextAlign(5) /** * Align text with the back edge of container */ val End = TextAlign(6) /** * Return a list containing all possible values of TextAlign. */ fun values(): List<TextAlign> = listOf(Left, Right, Center, Justify, Start, End) } }Copy the code

There are a couple of alignment definitions, and we’ll just look at the middle alignment, and you can experiment with the rest.

Line height

The lineHeight is set by the lineHeight argument, which is also TextUnit, so we set the size and spacing the same way as before:

Text(" Compose ", lineHeight = 80.sp)Copy the code

Text overflow

Handle TextOverflow cases using the overflow argument of type TextOverflow. Let’s have a look at its source code:

@Suppress("INLINE_CLASS_DEPRECATED") inline class TextOverflow internal constructor(internal val value: Int) { override fun toString(): String { return when (this) { Clip -> "Clip" Ellipsis -> "Ellipsis" Visible -> "Visible" else -> "Invalid" } } companion Object {/** * is basically equivalent to no processing, naturally truncated, */ Val Ellipsis = TextOverflow(1) /** * Ellipsis = TextOverflow(2) /** * */ val Visible = TextOverflow(3)}}Copy the code

The maximum number of rows is omitted. The default value is int.maxValue.

Text contains multiple styles

It is very common for text to contain multiple styles, such as different colors and font sizes for adjacent characters. If you need to set different styles in the same Text composable, you must use AnnotatedString, which can be annotated with any annotation style. Let’s see how it is constructed:

@Immutable class AnnotatedString internal constructor( val text: String, val spanStyles: List<Range<SpanStyle>> = emptyList(), val paragraphStyles: List<Range<ParagraphStyle>> = emptyList(), internal val annotations: List<Range<out Any>> = emptyList() ) : CharSequence {// omit... }Copy the code

It is a data class that contains a String value to represent literal content; A list of spanstyles for specifying spanstyles in specific parts of the text; A list that goes by ParagraphStyles, specifying text alignment, direction, line height, and text indentation styles.

TextStyle is used for Text composable items, while SpanStyle and ParagraphStyle are used for AnnotatedString. ParagraphStyle can be used for an entire paragraph, and SpanStyle can be applied at the character level. Once you tag one part of text with ParagraphStyle, that part is separated from the rest, similar to Android’s SpannableString.

Set text selection

Overall, is Text easier to use than TextView in Android View? Let’s look at how to set the text selection, text selection is long press the text pop-up copy, paste and other buttons, determine the text selection range.

By default, combinable items are not selectable, that is, the long-press copy selection is not supported. To do so, use SelectionContainer combinable items to encapsulate text elements:

We can see that the long press text supports select copy and other operations. If we want some characters in the text not to let the user to choose, then how to do it? We just need to use the DisableSelection combinable option to encapsulate the non-selectable text part:

As you can see, the text circled in red is now wrapped in DisableSelection, so it doesn’t support long press selection, and the rest of the text supports long press selection.

If we want to listen for Text clicks, we can add the Clickable modifier. If you want to get the location of a click, you need to use clickableText in cases where different operations are performed on different parts of the text.

ClickableText(text = AnnotatedString(" click "), onClick = {offset -> log. v("LM", "$offset")})Copy the code

When the user clicks on the composable item, if we want to add additional information to a part of the Text value, such as a particular character that jumps to the browser to open the URL, we can add an AnnotatedString:

Val annotatedText = buildAnnotatedString {appEnd (" click ") pushStringAnnotation(tag = "URL", Annotation = "http://www.baidu.com") withStyle(style = SpanStyle(color = color.blue)) {append("Url")} pop() // End ClickableText( text = annotatedText, style = TextStyle(fontSize = 30.sp), onClick = { offest -> annotatedText.getStringAnnotations(tag = "URL", start = offest, end = offest ).firstOrNull()?.let { annotation -> Log.v("LM", "click url " + annotation.item) } })Copy the code

We can see that when clicking “Url”, we can get the corresponding annotation. Item and print it out through the log:

2022-03-19 13:48:07.987 15329-15329/com.carey.compose V/LM: click url http://www.baidu.com
Copy the code

Okay, so today we learned about the use of Text and its properties. If you’re learning Compose, click “Like” and we’ll learn Compose together. We’ll cover learning about other controls later.