extended_text_field 0.3.9

extended_text_field #

pub package

extended official text field to quickly build special text like inline image or @somebody etc.

base on flutter sdk 1.7.8

Chinese blog

limitation #

  • Not support: it won't handle special text when TextDirection.rtl.

    Image position calculated by TextPainter is strange.

  • Not support:it won't handle special text when obscureText is true.

  • codes are base on flutter sdk 1.7.8, if any one find some codes are broken, please fix them base on your flutter version. it has not time to maintain codes for every version,sorry for that, and will update codes for stable flutter version as soon as possible.

How to use it. #

1. just to extend SpecialText and define your rule. #

code for @xxx

class AtText extends SpecialText {
  static const String flag = "@";
  final int start;

  /// whether show background for @somebody
  final bool showAtBackground;

  final BuilderType type;
  AtText(TextStyle textStyle, SpecialTextGestureTapCallback onTap,
      {this.showAtBackground: false, this.type, this.start})
      : super(flag, " ", textStyle, onTap: onTap);

  InlineSpan finishText() {
    // TODO: implement finishText
    TextStyle textStyle =
        this.textStyle?.copyWith(color: Colors.blue, fontSize: 16.0);

    final String atText = toString();

    if (type == BuilderType.extendedText)
      return TextSpan(
          text: atText,
          style: textStyle,
          recognizer: TapGestureRecognizer()
            ..onTap = () {
              if (onTap != null) onTap(atText);

    return showAtBackground
        ? BackgroundTextSpan(
            background: Paint()..color = Colors.blue.withOpacity(0.15),
            text: atText,
            actualText: atText,
            start: start,
            deleteAll: false,
            style: textStyle,
            recognizer: type == BuilderType.extendedText
                ? (TapGestureRecognizer()
                  ..onTap = () {
                    if (onTap != null) onTap(atText);
                : null)
        : SpecialTextSpan(
            text: atText,
            actualText: atText,
            start: start,
            deleteAll: false,
            style: textStyle,
            recognizer: type == BuilderType.extendedText
                ? (TapGestureRecognizer()
                  ..onTap = () {
                    if (onTap != null) onTap(atText);
                : null);

code for image

class EmojiText extends SpecialText {
  static const String flag = "[";
  final int start;
  EmojiText(TextStyle textStyle, {this.start})
      : super(EmojiText.flag, "]", textStyle);

  InlineSpan finishText() {
    // TODO: implement finishText
    var key = toString();
    if (EmojiUitl.instance.emojiMap.containsKey(key)) {
      //fontsize id define image height
      //size = 30.0/26.0 * fontSize
      final double size = 20.0;

      ///fontSize 26 and text height =30.0
      //final double fontSize = 26.0;

      return ImageSpan(AssetImage(EmojiUitl.instance.emojiMap[key]),
          actualText: key,
          imageWidth: size,
          imageHeight: size,
          start: start,
          deleteAll: true,
          fit: BoxFit.fill,
          margin: EdgeInsets.only(left: 2.0, top: 2.0, right: 2.0));

    return TextSpan(text: toString(), style: textStyle);

2. create your SpecialTextSpanBuilder. #

class MySpecialTextSpanBuilder extends SpecialTextSpanBuilder {
  /// whether show background for @somebody
  final bool showAtBackground;
  final BuilderType type;
      {this.showAtBackground: false, this.type: BuilderType.extendedText});

  TextSpan build(String data, {TextStyle textStyle, onTap}) {
    // TODO: implement build
    var textSpan = super.build(data, textStyle: textStyle, onTap: onTap);
    //for performance, make sure your all SpecialTextSpan are only in textSpan.children
    //extended_text_field will only check SpecialTextSpan in textSpan.children
    return textSpan;

  SpecialText createSpecialText(String flag,
      {TextStyle textStyle, SpecialTextGestureTapCallback onTap, int index}) {
    if (flag == null || flag == "") return null;
    // TODO: implement createSpecialText

    ///index is end index of start flag, so text start index should be index-(flag.length-1)
    if (isStart(flag, AtText.flag)) {
      return AtText(textStyle, onTap,
          start: index - (AtText.flag.length - 1),
          showAtBackground: showAtBackground,
          type: type);
    } else if (isStart(flag, EmojiText.flag)) {
      return EmojiText(textStyle, start: index - (EmojiText.flag.length - 1));
    } else if (isStart(flag, DollarText.flag)) {
      return DollarText(textStyle, onTap,
          start: index - (DollarText.flag.length - 1), type: type);
    } else if (isStart(flag, ImageText.flag)) {
      return ImageText(textStyle,
          start: index - (ImageText.flag.length - 1), type: type, onTap: onTap);
    return null;

enum BuilderType { extendedText, extendedTextField }

3.enjoy your nice text field #

input text will auto change to SpecialTextSpan and show in text field

            specialTextSpanBuilder: MySpecialTextSpanBuilder(
                showAtBackground: true, type: BuilderType.extendedTextField),
            controller: _textEditingController,
            maxLines: null,
            focusNode: _focusNode,
            decoration: InputDecoration(
                suffixIcon: GestureDetector(
                  onTap: () {
                    setState(() {
                      sessions.insert(0, _textEditingController.text);
                      _textEditingController.value =
                              text: "",
                              selection: TextSelection.collapsed(offset: 0),
                              composing: TextRange.empty);
                  child: Icon(Icons.send),
                contentPadding: EdgeInsets.all(12.0)),
            //textDirection: TextDirection.rtl,

more detail


  • improve codes base on v1.7.8
  • support WidgetSpan (ExtendedWidgetSpan)


  • update extended_text_library


  • remove un-used codes in extended_text_selection


  • update extended_text_library


  • update path_provider 1.1.0


  • uncomment getFullHeightForCaret method for 1.5.4-hotfix.2
  • corret selection handles visibility for _updateSelectionExtentsVisibility method


  • corret selection handles position for image textspan
  • StrutStyle strutStyle is obsoleted, it will lead to bugs for image span size.


  • fix selection handles blinking


  • take care when TextSpan children is null


  • update extended_text_library
  • update extended_text_library 1.remove caretIn parameter(SpecialTextSpan) 2.deleteAll parameter has the same effect as caretIn parameter(SpecialTextSpan)


  • fix caret position about image span
  • add caretIn parameter(whether caret can move into special text for SpecialTextSpan(like a image span or @xxxx)) for SpecialTextSpan


  • disabled informationCollector to keep backwards compatibility for now (ExtendedNetworkImageProvider)


  • fix caret position for last one image span
  • add image text demo
  • fix position for specialTex


  • fix caret position for image span


  • only iterate textSpan.children to find SpecialTextSpan


  • add BackgroundTextSpan, support to paint custom background


  • handle TextEditingValue's composing


  • improve codes to avoid unnecessary computation


  • override compareTo method in SpecialTextSpan and ImageSpan to fix issue that image span or special text span was error rendering


  • update limitation
  • improve codes


  • update limitation
  • improve codes


  • support special text amd inline image


example #

A new Flutter application.

Getting Started #

This project is a starting point for a Flutter application.

A few resources to get you started if this is your first Flutter project:

For help getting started with Flutter, view our online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference.

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:

  extended_text_field: ^0.3.9

2. Install it

You can install packages from the command line:

with Flutter:

$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:

import 'package:extended_text_field/extended_text_field.dart';
Describes how popular the package is relative to other packages. [more]
Code health derived from static analysis. [more]
Reflects how tidy and up-to-date the package is. [more]
Weighted score of the above. [more]
Learn more about scoring.

We analyzed this package on Jul 22, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.4.0
  • pana: 0.12.19
  • Flutter: 1.7.8+hotfix.3


Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Health suggestions

Fix lib/src/extended_text_field.dart. (-0.50 points)

Analysis of lib/src/extended_text_field.dart reported 1 hint:

line 17 col 8: Unused import: 'extended_text_selection.dart'.


Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0-dev.68.0 <3.0.0
extended_text_library ^0.4.2 0.4.2
flutter 0.0.0
Transitive dependencies
collection 1.14.11
meta 1.1.6 1.1.7
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies