Flutter's RichText
widget is a powerful tool that allows developers to create sophisticated text layouts with multiple styles, colors, and interactive elements within a single text block. Whether you're building a social media app with hashtags and mentions, a reading app with styled content, or simply want to add visual flair to your text, mastering RichText
is essential for creating polished Flutter applications.
What is RichText?
The RichText
widget displays text that uses multiple different styles. Unlike the basic Text
widget which applies a single style to the entire string, RichText
allows you to style individual portions of text differently using TextSpan
objects.
Basic RichText Structure
Every RichText
widget requires a TextSpan
as its text property. Here's the basic structure:
RichText(
text: TextSpan(
children: [
TextSpan(text: "Hello "),
TextSpan(
text: "World",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
)
Essential TextSpan Properties
Text Styling
-
text
: The actual text content -
style
: TextStyle object for formatting -
children
: List of nested TextSpan objects -
recognizer
: Gesture recognizer for tap interactions
Common TextStyle Properties
-
color
: Text color -
fontSize
: Size of the text -
fontWeight
: Bold, normal, etc. -
fontStyle
: Italic, normal -
decoration
: Underline, strikethrough, etc. -
backgroundColor
: Highlight color behind text
Real-World Examples
1. Social Media Post with Hashtags and Mentions
RichText(
text: TextSpan(
style: TextStyle(color: Colors.black, fontSize: 16),
children: [
TextSpan(text: "Just finished an amazing "),
TextSpan(
text: "#Flutter",
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.w500,
),
recognizer: TapGestureRecognizer()
..onTap = () => print("Hashtag tapped"),
),
TextSpan(text: " project! Thanks to "),
TextSpan(
text: "@FlutterDev",
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.w500,
),
recognizer: TapGestureRecognizer()
..onTap = () => print("Mention tapped"),
),
TextSpan(text: " for the inspiration! 🚀"),
],
),
)
2. Pricing Display with Strikethrough
RichText(
text: TextSpan(
style: TextStyle(fontSize: 18),
children: [
TextSpan(text: "Price: "),
TextSpan(
text: "\$99.99",
style: TextStyle(
color: Colors.grey,
decoration: TextDecoration.lineThrough,
),
),
TextSpan(text: " "),
TextSpan(
text: "\$49.99",
style: TextStyle(
color: Colors.green,
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
],
),
)
3. Terms and Conditions Link
RichText(
text: TextSpan(
style: TextStyle(color: Colors.black),
children: [
TextSpan(text: "By signing up, you agree to our "),
TextSpan(
text: "Terms and Conditions",
style: TextStyle(
color: Colors.blue,
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () => _openTermsAndConditions(),
),
TextSpan(text: " and "),
TextSpan(
text: "Privacy Policy",
style: TextStyle(
color: Colors.blue,
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () => _openPrivacyPolicy(),
),
],
),
)
4. Code Snippet Display
RichText(
text: TextSpan(
style: TextStyle(
fontFamily: 'Courier',
backgroundColor: Colors.grey[100],
),
children: [
TextSpan(
text: "void ",
style: TextStyle(color: Colors.blue),
),
TextSpan(
text: "main",
style: TextStyle(color: Colors.purple),
),
TextSpan(
text: "() {\n ",
style: TextStyle(color: Colors.black),
),
TextSpan(
text: "print",
style: TextStyle(color: Colors.blue),
),
TextSpan(
text: "('Hello, Flutter!');\n}",
style: TextStyle(color: Colors.black),
),
],
),
)
Advanced Techniques
1. Nested TextSpans
You can nest TextSpan
objects to create complex hierarchies:
RichText(
text: TextSpan(
text: "Welcome to ",
style: TextStyle(color: Colors.black),
children: [
TextSpan(
text: "Flutter",
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold,
),
children: [
TextSpan(
text: " Development",
style: TextStyle(
fontStyle: FontStyle.italic,
color: Colors.green,
),
),
],
),
],
),
)
2. Custom Gesture Recognizers
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
TapGestureRecognizer? _tapRecognizer;
@override
void initState() {
super.initState();
_tapRecognizer = TapGestureRecognizer()
..onTap = _handleTap;
}
@override
void dispose() {
_tapRecognizer?.dispose();
super.dispose();
}
void _handleTap() {
// Handle tap
}
@override
Widget build(BuildContext context) {
return RichText(
text: TextSpan(
text: "Click ",
children: [
TextSpan(
text: "here",
style: TextStyle(color: Colors.blue),
recognizer: _tapRecognizer,
),
],
),
);
}
}
3. Dynamic Text Building
Widget buildDynamicRichText(List<String> words) {
return RichText(
text: TextSpan(
children: words.map((word) {
if (word.startsWith('#')) {
return TextSpan(
text: word + ' ',
style: TextStyle(color: Colors.blue),
recognizer: TapGestureRecognizer()
..onTap = () => _handleHashtag(word),
);
} else if (word.startsWith('@')) {
return TextSpan(
text: word + ' ',
style: TextStyle(color: Colors.orange),
recognizer: TapGestureRecognizer()
..onTap = () => _handleMention(word),
);
} else {
return TextSpan(
text: word + ' ',
style: TextStyle(color: Colors.black),
);
}
}).toList(),
),
);
}
RichText vs Text.rich
Flutter also provides Text.rich()
constructor which is essentially a wrapper around RichText
with additional features from the Text
widget:
// Using Text.rich
Text.rich(
TextSpan(
children: [
TextSpan(text: "Hello "),
TextSpan(
text: "World",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
textAlign: TextAlign.center, // Additional Text widget properties
)
// Equivalent RichText
RichText(
textAlign: TextAlign.center,
text: TextSpan(
children: [
TextSpan(text: "Hello "),
TextSpan(
text: "World",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
)
Performance Tips
Dispose Gesture Recognizers: Always dispose of
TapGestureRecognizer
objects to prevent memory leaks.Reuse TextStyle Objects: Create TextStyle objects as constants when possible to reduce memory allocation.
Minimize Rebuilds: Use
const
constructors where possible and avoid creating new TextSpan objects in build methods.
// Good: Reusable styles
static const TextStyle _linkStyle = TextStyle(
color: Colors.blue,
decoration: TextDecoration.underline,
);
static const TextStyle _boldStyle = TextStyle(
fontWeight: FontWeight.bold,
);
Common Use Cases
1. Multi-language Support
RichText(
textDirection: TextDirection.rtl, // For RTL languages
text: TextSpan(
children: [
TextSpan(text: "مرحبا "),
TextSpan(
text: "بالعالم",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
)
2. Mathematical Expressions
RichText(
text: TextSpan(
children: [
TextSpan(text: "E = mc"),
TextSpan(
text: "2",
style: TextStyle(
fontSize: 12,
fontFeatures: [FontFeature.superscripts()],
),
),
],
),
)
FontFeature.superscripts() tells Flutter to render that character as a superscript (if supported by the font).
Make sure the font you're using supports superscripts. Most default fonts do, but custom fonts may not.
fontSize is reduced a bit on the superscript for visual consistency.
3. Highlight Search Results
Widget highlightSearchResults(String text, String query) {
if (query.isEmpty) {
return Text(text);
}
List<TextSpan> spans = [];
text.splitMapJoin(
RegExp(query, caseSensitive: false),
onMatch: (m) {
spans.add(TextSpan(
text: m[0],
style: TextStyle(backgroundColor: Colors.yellow),
));
return '';
},
onNonMatch: (n) {
spans.add(TextSpan(text: n));
return '';
},
);
return RichText(text: TextSpan(children: spans));
}
Conclusion
Flutter's RichText
widget is a powerful tool for creating styled, interactive text content. Key takeaways:
- Always dispose of gesture recognizers to prevent memory leaks
- Use consistent styling and reusable TextStyle objects
- Consider performance with large text content
- Perfect for social media apps, e-commerce, and content-rich applications
Master RichText to create professional, engaging user experiences in your Flutter apps📱!
✨ If you found this blog helpful and want to explore more Flutter projects, feel free to check out my GitHub repositories at Github — and don’t forget to follow for more updates!
Happy Coding!!💓
Top comments (0)