Sitemap

TextTheme in Flutter with less boilerplate using the extension methods.

Marco Nicotra
4 min readFeb 19, 2021

--

Photo by Alice Dietrich on Unsplash

The reason why.

Let’s be honest, as Flutter developers, we have a lot of issues and concerns with state management, business logic, code maintenance and refactoring, issues related to specific platforms… so who cares about styling best practice?

Well, you’ll arrive at a moment in your developer’s jouney when you’ll need to have more control about the app’s style. If you’re here, that moment is probably now.

The problem.

Look at the code below, it’s a simple mix of text widgets with a title, subtitle, an image and a description. It’s easy to see that I used the TextStyle widget for every Text to format the output with different font sizes, colors, weights and styles. This is a common (lazy) approach, especially when we start a project without a final UI design.

Now imagine managing all the Text widgets this way, with a lot of boilerplate, recurring TextStyle, and chaotic styling.
Yes, chaotic. Because now try to think: the UI designer arrives and asks you to change all the titles from 28 to 24 and the weight from bold to w900.
Good luck, find them all, and change the code everywhere. Pretty annoying.

If you have experience in web design, you know about CSS and how it works. We’ll now try to use the same approach using the Flutter ThemeData and TextTheme.

The TextTheme.

TextTheme is a Flutter widget (really?) that helps you to style the text in your app, very similar to the web approach.

When you create the MaterialApp root widget, you can define a ThemeData with textTheme, primaryTextTheme and accentTextTheme.

Ok but wait, let’s discuss what they are.

A ThemeData is, again, a widget that tells our MaterialApp how the UI widgets should look. You can define the scaffold background color, the AppBar style, or even if you want a light or dark theme.
Try to play with it, you’ll find a lot of useful theming.

ThemeData contains 3 versions of TextTheme, a default one, a primary and an accent version. What is the difference?
Not so different: the size and weight are the same everywhere by default.
The only difference is the color. Let’s see an example.

If you have a light theme with a white background, your main text should be dark. So the textTheme should use the Colors.black.

Sometimes you need more “accent”, for a title or a call to action. In this case, we will use our accent color, let’s pick Colors.red

But what if we box our text inside a container with a dark background color? Well, let’s use the primary color in this case to create a contrast, Colors.grey

Now that we have our 3 variations of color for the Text, let’s see what the theme will look like:

It’s not necessary to specify all the text styles, in fact, remember that each of these is used in the Material widgets. For example, headline2 to headline5 are used in Dialogs and DatePickers. So if you change one of these, the changes will be reflected inside the widgets. Now we know what will happen.
So far so good.

Let’s see how to use these styles in our custom widgets. In the first example, we saw a Text widget for the movie title. How to assign an accent headline1 style to it? We need the context to access the Theme:

Text(
'The Lord of the Rings',
style: Theme.of(context).accentTextTheme.headline1,
)

And if I want a small variation for my custom widget?
In that case, simply use .copyWith(). It creates a copy of the text style but with the given fields replaced with the new values.

Theme.of(context).textTheme.headline2.copyWith(color: Colors.red)

So you’ll have a text with the headline2 style but in red.

Time to use the extension method.

If you’ve arrived here, you’re probably thinking “really? Such a long instruction just for a style?”
Well, I asked myself that very question, and the answer is extension methods.

First of all, what is an extension method in Dart?
Extension methods, introduced in Dart 2.7, are a way to add functionality to existing libraries.
If you’re interested you’ll find many articles, in our case you just need to know that you can extend widgets, operators and classes.
A simple example on String class:

We’re extending String to add a new method .isValidEmail that will return a bool like other String method which you surely know: .isEmpty, .isNotEmpty

if(userEmail.isNotEmpty && userEmail.isValidEmail) 

else

It’s time to extend the BuildContext. Why the context? Because we need it to retrieve the theme with the Theme.of(context)

Now that the extension is ready, let’s use it on the first example:

Our code is now shorter, easier to read and maintain, but above all, it’s easy to change the text style in the entire app simply by making changes on the ThemeData.

That’s all!

Thanks for reading, if you liked it, and you would like to read more articles like this, clap your hands and leave a comment down below!

--

--

Marco Nicotra
Marco Nicotra

Written by Marco Nicotra

Flutter enthusiast & Pizza eater. Father of imWatching.app available on PlayStore and AppStore.

Responses (3)