buildTextSpan method

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

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