Welcome to the third part of Carthographing Jetpack Compose. In the previous episode we took a look at images and saw how to draw using Canvas(). Today we focus on text. As you will see, text-related features are present in quite a few packages. So, the aim of this post is to give you an understanding of what to find where.
Easy to use
Showing text in Jetpack Compose is really easy. The following code snippet will give you a centered italic text. Its size is provided as scale-independent pixels (sp).
Text(
modifier = Modifier.fillMaxWidth(),
text = "Hello Compose",
textAlign = TextAlign.Center,
fontStyle = FontStyle.Italic,
fontSize = 64.sp
)
Text() belongs to androidx.compose.material. If you don't need the Material goodness, there is a nice BasicText() composable in androidx.compose.foundation.text.
BasicText(
text = "Hello Compose"
)
Have you noticed that I did not pass textAlign, fontStyle or fontSize? Well, you can't. As parameters, that is. To configure the appearance of your text you use annotated strings. Take a look:
val l = mutableListOf<AnnotatedString.Range<SpanStyle>>()
l.add(AnnotatedString.Range(SpanStyle(Color.Red), 0, 5))
l.add(AnnotatedString.Range(SpanStyle(Color.Blue), 6, 13))
BasicText(
text = AnnotatedString(
text = "Hello Compose",
spanStyles = l
)
)
The immutable class AnnotatedString belongs to androidx.compose.ui.text. The docs say:
The basic data structure of text with multiple styles. To
construct anAnnotatedStringyou can useBuilder.
The parameter spanStyles is
a list of
Ranges that specifiesSpanStyles on certain
portion of the text. These styles will be applied in the order
of the list. And theSpanStyles applied later can override the
former styles.
My example defines two distinct Ranges inside the annotated string. Ranges contain an item of some type (for example SpanStyle), a start (when the range takes effect), and an end. Please note that end refers to the position where the item is no longer in effect. My ranges differ in color. SpanStyle can be configured extensively, for example using fontSize, fontStyle, or background.
Now let's see how the builder the docs mentioned works:
BasicText(
text = buildAnnotatedString {
withStyle(
style = SpanStyle(
fontSize = 64.sp,
color = Color.Yellow,
background = Color.LightGray
)
) {
append("Hello Compose")
}
addStyle(
style = ParagraphStyle(textAlign = TextAlign.Center),
start = 0, end = length
)
}
)
buildAnnotatedString() belongs to androidx.compose.ui.text, just like AnnotatedString. In fact they currently share the same source file, AnnotatedString.kt. The class AnnotatedString.Builder allows the construction of an AnnotatedString using methods such as withStyle(), append(), and addStyle(). My example sets the basic appearance using withStyle() and adds th text with append(). addStyle() centers my text. Have you noticed end = length? length saves you from calculating the length of the text on your own.
Clickable text
You can make a text clickable the same way as you would with any other composable.
BasicText(
text = "Hello Compose",
modifier = Modifier.clickable {
println("Hello")
}
)
This is super convenient for things like Click to start. But what if you need to know which part of the text the user has clicked?
ClickableText(
text = AnnotatedString(text = "Click here"),
onClick = {
println(it)
}
)
The composable ClickableText() belongs to androidx.compose.foundation.text. The docs say:
A continent version of
BasicTextcomponent to be able to
handle click event on the text.This is a shorthand of
BasicTextwithpointerInputto be
able to handle click event easily.
onClick is executed when users click the text. The callback receives clicked character's offset.
Other text-related functions
So far I have shown you text-related functions inside Jetpack Compose. But there is another Jetpack (not compose) package dealing with text: androidx.core.text. It contains some nice extension functions, e.g. htmlEncode(). Let's see how it works.
So the extension function passes its parameter to TextUtils.htmlEncode(). The class TextUtils belongs to package android.text. We thus jump into the Android framework. It is worth mentioning that androidx.core.text contains a class called TextUtilsCompat which also features a static htmlEncode() function. If Jetpack Compose used this, it might eliminate one dependency to the platform, which could help porting to Compose for Desktop. I'll follow up on this shortly.
But what does htmlEncode() do? The Android docs say:
Html-encode the string.
This leaves room for explanations. 😎 Let's peek into the androidx.core.text.TextUtilsCompat version.
So we learn two things:
-
htmlEncode()makes certain characters html-friendly - On newer platform versions even
TextUtilsCompatinvokes the platform so my assumption stated above does not hold. To do so the code would need to be altered to always doing theelsepart.
Before finishing this part I would like to mention that extension function capitalize() is available in both kotlin.text (yet another text-related package) and androidx.compose.ui.text. The first one is deprecated.
The second one is not. So in your Compose apps you might consider using androidx.compose.ui.text.capitalize() which receives a androidx.compose.ui.text.intl.Locale.
Conclusion
Text support in Jetpack Compose is distributed over quite a few packages and sub packages. Regarding your Compose apps the most important decision will be if you use the Material version or the more basic ones. Did I miss something important? Kindly share your thoughts in the comments.





Top comments (0)