buildTextSpan method

  1. @override
TextSpan buildTextSpan()

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() {
  if (widget.obscureText) {
    String text = _value.text;
    text = widget.obscuringCharacter * text.length;
    // Reveal the latest character in an obscured field only on mobile.
    // Newer versions of iOS (iOS 15+) no longer reveal the most recently
    // entered character.
    const Set<TargetPlatform> mobilePlatforms = <TargetPlatform>{
      TargetPlatform.android,
      TargetPlatform.fuchsia,
    };
    final bool brieflyShowPassword =
        WidgetsBinding.instance.platformDispatcher.brieflyShowPassword &&
            mobilePlatforms.contains(defaultTargetPlatform);
    if (brieflyShowPassword) {
      final int? o =
          _obscureShowCharTicksPending > 0 ? _obscureLatestCharIndex : null;
      if (o != null && o >= 0 && o < text.length) {
        text = text.replaceRange(o, o + 1, _value.text.substring(o, o + 1));
      }
    }
    return TextSpan(style: _style, text: text);
  }

  // zmtzawqlp
  if (_value.composing.isValid && !widget.readOnly) {
    final TextStyle composingStyle = widget.style.merge(
      const TextStyle(decoration: TextDecoration.underline),
    );
    final String beforeText = _value.composing.textBefore(_value.text);
    final String insideText = _value.composing.textInside(_value.text);
    final String afterText = _value.composing.textAfter(_value.text);

    if (supportSpecialText) {
      final TextSpan before = extendedEditableText.specialTextSpanBuilder!
          .build(beforeText, textStyle: widget.style);
      final TextSpan after = extendedEditableText.specialTextSpanBuilder!
          .build(afterText, textStyle: widget.style);

      final List<InlineSpan> children = <InlineSpan>[];

      children.add(before);

      children.add(TextSpan(
        style: composingStyle,
        text: insideText,
      ));

      children.add(after);

      return TextSpan(style: widget.style, children: children);
    }

    return TextSpan(style: widget.style, children: <TextSpan>[
      TextSpan(text: beforeText),
      TextSpan(
        style: composingStyle,
        text: insideText,
      ),
      TextSpan(text: afterText),
    ]);
  }

  if (supportSpecialText) {
    final TextSpan? specialTextSpan = extendedEditableText
        .specialTextSpanBuilder
        ?.build(_value.text, textStyle: widget.style);
    if (specialTextSpan != null) {
      return specialTextSpan;
    }
  }

  if (_placeholderLocation >= 0 &&
      _placeholderLocation <= _value.text.length) {
    final List<_ScribblePlaceholder> placeholders = <_ScribblePlaceholder>[];
    final int placeholderLocation = _value.text.length - _placeholderLocation;
    if (_isMultiline) {
      // The zero size placeholder here allows the line to break and keep the caret on the first line.
      placeholders.add(const _ScribblePlaceholder(
          child: SizedBox.shrink(), size: Size.zero));
      placeholders.add(_ScribblePlaceholder(
          child: const SizedBox.shrink(),
          size: Size(renderEditable.size.width, 0.0)));
    } else {
      placeholders.add(const _ScribblePlaceholder(
          child: SizedBox.shrink(), size: Size(100.0, 0.0)));
    }
    return TextSpan(
      style: _style,
      children: <InlineSpan>[
        TextSpan(text: _value.text.substring(0, placeholderLocation)),
        ...placeholders,
        TextSpan(text: _value.text.substring(placeholderLocation)),
      ],
    );
  }
  final bool withComposing = !widget.readOnly && _hasFocus;
  if (_spellCheckResultsReceived) {
    // If the composing range is out of range for the current text, ignore it to
    // preserve the tree integrity, otherwise in release mode a RangeError will
    // be thrown and this EditableText will be built with a broken subtree.
    assert(!_value.composing.isValid ||
        !withComposing ||
        _value.isComposingRangeValid);

    final bool composingRegionOutOfRange =
        !_value.isComposingRangeValid || !withComposing;

    return buildTextSpanWithSpellCheckSuggestions(
      _value,
      composingRegionOutOfRange,
      _style,
      _spellCheckConfiguration.misspelledTextStyle!,
      spellCheckResults!,
    );
  }

  // Read only mode should not paint text composing.
  return widget.controller.buildTextSpan(
    context: context,
    style: _style,
    withComposing: withComposing,
  );
}