Text widget with formatted text using tags. Makes it easier to use formatted text in multilingual applications.
Formatting is set in the text using xml tags, for which styles and other behaviors are defined separately. It is also possible to insert icons and widgets through tags.
You can set the click handler for the tag, through a tag definition class StyledTextActionTag
.
Attention! The way of specifying the styles and behavior of tags has changed. See how to migrate from version 2.0.
Attention! The default value of the newLineAsBreaks
parameter has been changed, now it is enabled by default and line breaks are not ignored in the text.
In your flutter project add the dependency:
dependencies:
...
styled_text: ^[version]
Import package:
import 'package:styled_text/styled_text.dart';
Tag attributes must be enclosed in double quotes, for example: <link href="https://flutter.dev">
.
You need to escape specific XML characters in text:
Original character Escaped character
------------------ -----------------
" "
' '
& &
< <
> >
<space> &space;
By default, line breaks are not ignored, all line breaks \n
are automatically translated into the <br/>
tag. To disable this behavior, you can set the newLineAsBreaks
parameter to false
and insert the <br/>
tag where you want to break to a new line.
StyledText(
text: 'Test: <bold>bold</bold> text.',
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: FontWeight.bold)),
},
)
StyledText(
text: 'Test: <bold>bold</bold> and <red>red color</red> text.',
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: FontWeight.bold)),
'red': StyledTextTag(style: TextStyle(fontWeight: FontWeight.bold, color: Colors.red)),
},
)
StyledText(
text: 'Text with alarm <alarm/> icon.',
tags: {
'alarm': StyledTextIconTag(Icons.alarm),
},
)
StyledText(
text: 'Text with <link href="https://flutter.dev">link</link> inside.',
tags: {
'link': StyledTextActionTag(
(String? text, Map<String?, String?> attrs) => {
final String link = attrs['href'];
print('The "$link" link is tapped.');
},
style: TextStyle(decoration: TextDecoration.underline),
),
},
)
StyledText(
text: 'Text with custom <color text="#ff5500">color</color> text.',
tags: {
'color': StyledTextCustomTag(
baseStyle: TextStyle(fontStyle: FontStyle.italic),
parse: (baseStyle, attributes) {
if (attributes.containsKey('text') &&
(attributes['text'].substring(0, 1) == '#') &&
attributes['text'].length >= 6) {
final String hexColor = attributes['text'].substring(1);
final String alphaChannel = (hexColor.length == 8) ? hexColor.substring(6, 8) : 'FF';
final Color color = Color(int.parse('0x$alphaChannel' + hexColor.substring(0, 6)));
return baseStyle.copyWith(color: color);
} else {
return baseStyle;
}
}),
},
)
StyledText(
text: 'Text with <input/> inside.',
tags: {
'input': StyledTextWidgetTag(
TextField(
decoration: InputDecoration(
hintText: 'Input',
),
),
size: Size.fromWidth(200),
constraints: BoxConstraints.tight(Size(100, 50)),
),
},
)
StyledText.selectable(
text: 'Test: <bold>bold</bold> text.',
tags: {
'bold': StyledTextTag(style: TextStyle(fontWeight: FontWeight.bold)),
},
)
Starting from version 3.0, the way of specifying styles and behavior for tags has changed. Now for this you need to use the tags
parameter instead of styles
and another set of classes to define styles and behavior.
Below are examples of converting old code to new.
OLD
StyledText(
text: 'Example: <b>bold</b> text.',
styles: {
'b': TextStyle(fontWeight: FontWeight.bold),
},
)
NEW
StyledText(
text: 'Example: <b>bold</b> text.',
tags: {
'b': StyledTextTag(style: TextStyle(fontWeight: FontWeight.bold)),
},
)
OLD
StyledText(
text: 'Text with alarm <alarm/> icon.',
styles: {
'alarm': IconStyle(Icons.alarm),
},
)
NEW
StyledText(
text: 'Text with alarm <alarm/> icon.',
tags: {
'alarm': StyledTextIconTag(Icons.alarm),
},
)
OLD
StyledText(
text: 'Text with <link href="https://flutter.dev">link</link> inside.',
styles: {
'link': ActionTextStyle(
decoration: TextDecoration.underline,
onTap: (_, attrs) => _openLink(context, attrs),
),
},
)
NEW
StyledText(
text: 'Text with <link href="https://flutter.dev">link</link> inside.',
tags: {
'link': StyledTextActionTag(
(_, attrs) => _openLink(context, attrs),
style: TextStyle(decoration: TextDecoration.underline),
),
},
)
OLD
StyledText(
text: 'Text with custom <color text="#ff5500">color</color> text.',
styles: {
'color': CustomTextStyle(
baseStyle: TextStyle(fontStyle: FontStyle.italic),
parse: (baseStyle, attributes) {
// Parser code here...
}),
},
)
NEW
StyledText(
text: 'Text with custom <color text="#ff5500">color</color> text.',
tags: {
'color': StyledTextCustomTag(
baseStyle: TextStyle(fontStyle: FontStyle.italic),
parse: (baseStyle, attributes) {
// Parser code here...
}),
},
)
Run this command:
With Flutter:
$ flutter pub add styled_text
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
styled_text: ^8.1.0
Alternatively, your editor might support flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:styled_text/styled_text.dart';
import 'package:flutter/material.dart';
import 'package:styled_text/styled_text.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'StyledText Demo',
theme: ThemeData(
primarySwatch: Colors.teal,
),
home: const DemoPage(),
);
}
}
class DemoPage extends StatelessWidget {
const DemoPage({super.key});
void _alert(BuildContext context, {String text = 'Tapped'}) {
showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: Text(text),
actions: <Widget>[
TextButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
void _openLink(BuildContext context, Map<String?, String?> attrs) {
final String? link = attrs['href'];
showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Open Link'),
content: Text(link ?? 'Unknown link'),
actions: <Widget>[
TextButton(
child: const Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
@override
Widget build(BuildContext context) {
return SelectionArea(
child: Scaffold(
appBar: AppBar(
title: const Text('StyledText Demo'),
),
body: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(vertical: 32),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
// Simple formatted text
StyledText(
text: 'Test: <b>bold</b> text.',
tags: {
'b': StyledTextTag(
style: const TextStyle(fontWeight: FontWeight.bold),
),
},
),
// Nested multiple styles
StyledText(
text: 'Test: <b>bold <i>italic</i> bold</b> text.',
tags: {
'b': StyledTextTag(
style: const TextStyle(fontWeight: FontWeight.bold),
),
'i': StyledTextTag(
style: const TextStyle(fontStyle: FontStyle.italic),
),
},
),
// Text with quotes
StyledText(
text: 'Quote test: <b>"bold"</b> text.',
tags: {
'b': StyledTextTag(
style: const TextStyle(fontWeight: FontWeight.bold),
),
},
),
// Multiline text without breaks
const SizedBox(height: 20),
StyledText(
newLineAsBreaks: false,
text: """Multiline text
(wo breaks)""",
tags: {
'b': StyledTextTag(
style: const TextStyle(fontWeight: FontWeight.bold),
),
},
),
// Multiline text with breaks
const SizedBox(height: 20),
StyledText(
text: """Multiline text
(with breaks)""",
tags: {
'b': StyledTextTag(
style: const TextStyle(fontWeight: FontWeight.bold),
),
},
),
// Text with icon
const SizedBox(height: 20),
StyledText(
text: 'Text with alarm <alarm/> icon.',
tags: {
'alarm': StyledTextIconTag(
Icons.alarm,
color: Colors.teal,
size: 18,
onTap: (text, attributes) =>
_alert(context, text: 'Alarm Tapped'),
),
},
),
// Text with icon inside styled text
const SizedBox(height: 20),
StyledText(
text: 'Text with <red>alarm <alarm/> icon</red>.',
tags: {
'red': StyledTextTag(
style: const TextStyle(color: Colors.red),
),
'alarm': StyledTextIconTag(
Icons.alarm,
color: Colors.teal,
size: 18,
onTap: (text, attributes) =>
_alert(context, text: 'Alarm Tapped'),
),
},
),
// Text with link
const SizedBox(height: 20),
StyledText(
text:
'Text with <link href="https://flutter.dev">link</link> inside.',
tags: {
'link': StyledTextActionTag(
(_, attrs) => _openLink(context, attrs),
style:
const TextStyle(decoration: TextDecoration.underline),
),
},
),
// Text with action
const SizedBox(height: 20),
StyledText(
text:
'Text with <action><red>red</red> action</action> inside.',
tags: {
'red': StyledTextTag(
style: const TextStyle(color: Colors.red),
),
'action': StyledTextActionTag(
(text, attributes) => _alert(context),
style:
const TextStyle(decoration: TextDecoration.underline),
),
},
),
// Text with superscript
const SizedBox(height: 20),
StyledText(
text: "Famous equation: E=mc<sup>2</sup>",
tags: {
'sup': StyledTextWidgetBuilderTag(
(_, attributes, textContent) {
return Transform.translate(
offset: const Offset(0.5, -4),
child: Text(
textContent ?? "",
textScaleFactor: 0.85,
),
);
},
),
},
),
// Text with subscript
const SizedBox(height: 20),
StyledText(
text: "The element of life: H<sub>2</sub>0",
tags: {
'sub': StyledTextWidgetBuilderTag(
(_, attributes, textContent) {
return Transform.translate(
offset: const Offset(0.5, 4),
child: Text(
textContent ?? "",
textScaleFactor: 0.8,
),
);
},
),
},
),
// Text with widget
const SizedBox(height: 20),
StyledText(
text: 'Text with <input/> inside.',
tags: {
'input': StyledTextWidgetTag(
const TextField(
decoration: InputDecoration(
hintText: 'Input',
),
),
size: const Size.fromWidth(200),
constraints: BoxConstraints.tight(const Size(100, 50)),
),
},
),
const Divider(height: 40),
// Selectable text
StyledText.selectable(
text: 'Test: selectable <b>bold</b> text.',
tags: {
'b': StyledTextTag(
style: const TextStyle(fontWeight: FontWeight.bold),
),
},
),
const Divider(height: 40),
// Text with custom color tag
StyledText(
text:
'Text with custom <color text="#ff5500">color</color> text.',
tags: {
'color': StyledTextCustomTag(
baseStyle: const TextStyle(fontStyle: FontStyle.italic),
parse: (baseStyle, attributes) {
if (attributes.containsKey('text') &&
(attributes['text']!.substring(0, 1) == '#') &&
attributes['text']!.length >= 6) {
final String hexColor =
attributes['text']!.substring(1);
final String alphaChannel = (hexColor.length == 8)
? hexColor.substring(6, 8)
: 'FF';
final Color color = Color(int.parse(
'0x$alphaChannel${hexColor.substring(0, 6)}'));
return baseStyle?.copyWith(color: color);
} else {
return baseStyle;
}
}),
},
),
],
),
),
),
),
);
}
}
Download details:
Author: amazingsoftworks.com
Source: https://github.com/andyduke/styled_text_package