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