Makes It Easier to Use formatted Text in Flutter Multilingual Applications

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.

Getting Started 

In your flutter project add the dependency:

dependencies:
  ...
  styled_text: ^[version]

Import package:

import 'package:styled_text/styled_text.dart';

Escaping & special characters 

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
------------------  -----------------
"                   &quot;
'                   &apos;
&                   &amp;
<                   &lt;
>                   &gt;
<space>             &space;

Line breaks 

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.

Usage examples 

An example of making parts of text bold: 

StyledText(
  text: 'Test: <bold>bold</bold> text.',
  tags: {
    'bold': StyledTextTag(style: TextStyle(fontWeight: FontWeight.bold)),
  },
)

Example of highlighting a part of the text by different styles: 

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)),
  },
)

Example of inserting icons into the text: 

StyledText(
  text: 'Text with alarm <alarm/> icon.',
  tags: {
    'alarm': StyledTextIconTag(Icons.alarm),
  },
)

Example of using a tag handler: 

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),
    ),
  },
)

Example of using a custom tag attributes handler, highlights text with the color specified in the "text" attribute of the tag: 

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;
          }
        }),
  },
)

An example of inserting an input field widget in place of a tag: 

StyledText(
  text: 'Text with <input/> inside.',
  tags: {
    'input': StyledTextWidgetTag(
      TextField(
        decoration: InputDecoration(
          hintText: 'Input',
        ),
      ),
      size: Size.fromWidth(200),
      constraints: BoxConstraints.tight(Size(100, 50)),
    ),
  },
)

An example of using a widget with the ability to select rich text: 

StyledText.selectable(
  text: 'Test: <bold>bold</bold> text.',
  tags: {
    'bold': StyledTextTag(style: TextStyle(fontWeight: FontWeight.bold)),
  },
)

Migration from version 2.0 

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.

Specifying the text style 

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)),
  },
)

Specifying the icon 

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),
  },
)

Specifying a tap handler 

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),
    ),
  },
)

Specifying a custom parser for attributes and creating a style 

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...
        }),
  },
)

Use this package as a library

Depend on it

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.

Import it

Now in your Dart code, you can use:

import 'package:styled_text/styled_text.dart';

example/lib/main.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>&quot;bold&quot;</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

#flutter #android #ios 

Makes It Easier to Use formatted Text in Flutter Multilingual Applications
1.15 GEEK