[MUSIC PLAYING]
ALEJANDRA STAMATO: Hi there.
I'm Alejandra Stamato, engineer on the Android Developer
Relations team.
In this talk, we'll take Jetchat, our sample chat app,
and style the chat bubble, customizing
the font using downloadable and variable fonts.
We'll also make the message expandable
when it is longer than a certain number of lines.
Then we'll move on to styling the message box.
How about giving it a gradient border, a cursor
that changes color as you type, or a custom decorated box?
So let's get started.
Our designer has given us a design
using Material 3 components.
We'll start by configuring the app's typography, which
allow us to tweak the Material default text
styles to match our designs.
You do this by creating TextStyle blocks
for the style you need to specify,
like bodyLarge, Medium, and Small,
and changing what's needed.
Each TextStyle allows you to style
your whole text with parameters like fontFamily,
Weight, Size, but also your whole paragraph,
with lineHeight, letterSpacing, and many more.
So now we have a bodyLarge style configured
with all these parameters.
It's time to start our chat bubble.
Here's the design we want to implement.
So open the text composable of the chat message,
and set the style parameter to be MaterialTheme.ty
pography.bodyLarge.
And that's it.
You're good to go.
If you need to customize a specific parameter
for your text-- for example, color--
we can copy the style and customize what you need,
similar to a data class.
Alternatively, the text composable
exposes the most common styling attributes like color,
fontSize, fontFamily as parameters
so you can set them directly.
Note that supplying a parameter directly
will override it in the style.
Next up, the Send button.
We implement this with a button and a text composable inside.
When we run the app, we notice that without configuring
any style, the text knows how to style itself as a button--
in bold, white color, maybe even different letter spacing.
So let's take a look to see how Material button does this.
One great thing about Compose is that you
can navigate the source code, and it's
all very readable Kotlin code.
Inside Button composable, we'll find a code
to ProvideTextStyle, which creates a composition
local configuring LocalTextStyle.current to be
labelLarge.
If we now take a look at the text composable,
we'll see that style defaults to LocalTextStyle.current,
meaning it adopts the style configured
in the current portion of the composition-- in this case,
labelLarge from the button.
Similarly, the default text color
is provided by LocalContentColor,
based upon the color of the button,
so you automatically get light text
on dark buttons and vice versa.
This mechanism allows Material to style your Material
components for you across your app
without you needing to be explicit if you don't need to.
Now let's customize the chat bubble further.
If text doesn't fit our available space,
we show an ellipsis and a button to view the entire text.
So first we configure the text with two parameters-- maxLines
set to eight lines and Overflow type ellipsis.
Now our text shows an ellipsis if it's
longer than eight lines.
And what if we have more than eight lines of text?
We add the button to expand the bubble
and see the whole message.
To do this, we can use onTextLayout lambda,
which returns text layer results with measurement
information captured after the layout phase.
By querying hasVisualOverflow, you
can change your UI just in time, displaying the More button.
You don't admit UI inside onTextLayout lambda
because this call is not part of the composition.
Instead, you can change a state variable
triggering a recomposition, and then
decide to show a button or not based
on the value of this state variable.
All right, now let's play with fonts a little bit
and configure the chat message font.
Let's try the Lobster Two font, which looks like this.
You could bundle the font increase in the APK size,
or instead you can use a new downloadable font API.
This also makes the font available for other apps that
may require it.
Let's see how to use it.
You just configure your Google font provider,
pick your Google font, and build your font family
as a chain of font fallbacks in case any font in the chain
fails to load.
And set the font in your typography
or in your individual texts.
The font is downloaded when you need it without you having
to worry about any callbacks.
You may optionally pre-fetch fonts
to make sure they are available before first usage.
To do this, get the local fontFamilyResolver
in composition and use the preload method asynchronously,
which will suspend until the font family is fully preloaded
or fails.
If successful, the font is cached and ready to be used.
Be mindful that fonts might take up to several seconds
to time out.
Check out the docs to learn more about fontFamilyResolver API.
If you want to up your font game,
variable fonts is ready to use from Compose 1.3 for Android 0
and above.
A variable font allows you to take the same font file
and configure it in multiple ways or axis
to create dramatically different styles.
Here we're using a variable font called recursive, which
has a standard axis like Weight and Slant,
but also custom axis like Casual, Monospace, and Cursive.
How do we configure our variable font in code?
You download the file locally and set the axis
you need using the FontVariation API.
And then you add this font to your font family.
So for instance, setting weight, slant, and a custom
casual axis like this results in this design.
Check out the FontVariation API docs to learn more.
OK, one more feature for our chat bubble.
We want to be able to style text wrapped
in [INAUDIBLE] and style it differently with code format,
changing the font family and background color.
We've been talking about styling your entire text
using TextStyle.
Now, AnnotatedString allows us to style parts
of our text or paragraph.
We start by using buildAnnotatedString block.
We create a spanStyle with FontFamily.Monospace
and a new background color.
Use the withStyle method to apply the style to the portion
of the text we need to style.
And finally, we append it to the final text.
All right, now it's time to customize our message box.
TextField allows for several styling options, including
redefining all default colors.
Here we're setting the focused and unfocused indicator
color for this TextField to be green and orange.
You can customize the colors of all TextField components
like cursor, content, label, icons, and selection colors,
like selection handle color, and in all their states--
focused, unfocused, disabled, and error modes.
But what if we have this design here with a full border
instead?
We can use outlinedTextField for this
and configure all colors, just like we did before,
with outlinedTextFieldColors.
If you're looking to customize the border of your box
even further, the border modifier will help you.
Here we're using a TextField.
When we create a border stroke, which receives a brush--
in our case, we'll use a gradient brush--
configure the thickness and shape of our border
to be CutCornerShape.
But you might receive a design that deviates entirely
from Material, with custom colors, cursor, decorations.
In this case, you can use a different component altogether.
So far, we've worked with text or TextField, which
are Material Theme components and sit at the top layer
of the compose architecture.
But if you need more customization,
you can drop down and use BasicText and BasicTextField
from the foundation layer.
So here we have a design in which our cursor changes color
as you type, from green to red, as you get closer
to the end of the line.
BasicTextField has a cursorBrush parameter
that will allow you to style the cursor color with a brush API,
and you can define a solid color.
Or, in our case, we define a gradient.
So as we approach the character limit,
our cursor changes color.
Lastly, what if we want to completely customize
the display of our TextField?
Here, we're setting a custom background and leading icon.
We can use BasicTextField again and set a decorationBox
to achieve this.
This allows us to add declaration
around the TextField, such as icons, dividers, placeholders,
and so on.
We create a row with modifiers like background
to configure shape, color, and padding, add the Jetchat icon,
and then add the input, which is placed next to it in the row.
And we're done!
We barely scratched the surface of what you
can do with text in Compose.
To learn more, go check out our docs and Jetchat's code
on the following links.
You can also check our text blog posts on the new LineHeight
API, TextField state management, and brush API integration
with text style and animations.
That's it.
I would close this talk with a font joke, but to be honest,
I'm not bold enough.
Hope you learned something new, and stay tuned,
as there is lots coming up for text in Jetpack Compose.
Thank you.
[MUSIC PLAYING]