buildTextSpan method

  1. @override
TextSpan buildTextSpan({
  1. required BuildContext context,
  2. TextStyle? style,
  3. required bool withComposing,
})
override

Builds TextSpan from current editing value.

By default makes text in composing range appear as underlined. Descendants can override this method to customize appearance of text.

Implementation

@override
TextSpan buildTextSpan(
    {required BuildContext context,
    TextStyle? style,
    required bool withComposing}) {
  final provider = Data.maybeOf<_ChipProvider<T>>(context);
  final theme = ComponentTheme.maybeOf<ChipInputTheme>(context);
  final spacing = theme?.spacing ?? 4.0;
  if (provider != null) {
    final bool composingRegionOutOfRange =
        !value.isComposingRangeValid || !withComposing;

    if (composingRegionOutOfRange) {
      List<InlineSpan> children = [];
      String text = value.text;
      StringBuffer buffer = StringBuffer();
      for (int i = 0; i < text.length; i++) {
        int codeUnit = text.codeUnitAt(i);
        if (codeUnit >= _chipStart && codeUnit <= _chipEnd) {
          // Flush buffer
          if (buffer.isNotEmpty) {
            children.add(TextSpan(style: style, text: buffer.toString()));
            buffer.clear();
          }
          T? chip = _chipMap[codeUnit - _chipStart];
          Widget? chipWidget =
              chip == null ? null : provider.buildChip(context, chip);
          if (chipWidget != null) {
            bool previousIsChip = i > 0 &&
                text.codeUnitAt(i - 1) >= _chipStart &&
                text.codeUnitAt(i - 1) <= _chipEnd;
            bool nextIsChip = i < text.length - 1 &&
                text.codeUnitAt(i + 1) >= _chipStart &&
                text.codeUnitAt(i + 1) <= _chipEnd;
            children.add(ChipSpan<T>(
              value: chip as T,
              alignment: PlaceholderAlignment.middle,
              child: Padding(
                padding: EdgeInsets.only(
                  left: previousIsChip
                      ? spacing / 2
                      : i == 0
                          ? 0
                          : spacing,
                  right: nextIsChip ? spacing / 2 : spacing,
                ),
                child: chipWidget,
              ),
            ));
          }
        } else {
          buffer.writeCharCode(codeUnit);
        }
      }
      // Flush remaining buffer
      if (buffer.isNotEmpty) {
        children.add(TextSpan(style: style, text: buffer.toString()));
      }
      return TextSpan(style: style, children: children);
    }

    final TextStyle composingStyle =
        style?.merge(const TextStyle(decoration: TextDecoration.underline)) ??
            const TextStyle(decoration: TextDecoration.underline);
    List<InlineSpan> children = [];
    String text = value.text;
    StringBuffer buffer = StringBuffer();
    for (int i = 0; i < text.length; i++) {
      int codeUnit = text.codeUnitAt(i);
      if (codeUnit >= _chipStart && codeUnit <= _chipEnd) {
        // Flush buffer
        if (buffer.isNotEmpty) {
          children.add(TextSpan(style: style, text: buffer.toString()));
          buffer.clear();
        }
        T? chip = _chipMap[codeUnit - _chipStart];
        Widget? chipWidget =
            chip == null ? null : provider.buildChip(context, chip);
        if (chipWidget != null) {
          bool previousIsChip = i > 0 &&
              text.codeUnitAt(i - 1) >= _chipStart &&
              text.codeUnitAt(i - 1) <= _chipEnd;
          bool nextIsChip = i < text.length - 1 &&
              text.codeUnitAt(i + 1) >= _chipStart &&
              text.codeUnitAt(i + 1) <= _chipEnd;
          children.add(ChipSpan<T>(
            value: chip as T,
            alignment: PlaceholderAlignment.middle,
            child: Padding(
              padding: EdgeInsets.only(
                left: previousIsChip
                    ? spacing / 2
                    : i == 0
                        ? 0
                        : spacing,
                right: nextIsChip ? spacing / 2 : spacing,
              ),
              child: chipWidget,
            ),
          ));
        }
      } else {
        // Check if current index is within composing range
        if (i >= value.composing.start && i < value.composing.end) {
          // Flush buffer
          if (buffer.isNotEmpty) {
            children.add(TextSpan(style: style, text: buffer.toString()));
            buffer.clear();
          }
          children.add(TextSpan(
              style: composingStyle, text: String.fromCharCode(codeUnit)));
        } else {
          buffer.writeCharCode(codeUnit);
        }
      }
    }
    // Flush remaining buffer
    if (buffer.isNotEmpty) {
      children.add(TextSpan(style: style, text: buffer.toString()));
    }
    return TextSpan(style: style, children: children);
  }
  return super.buildTextSpan(
      context: context, style: style, withComposing: withComposing);
}