I’m trying to add a thick custom underline behind the text without breaking the text wrapping behaviour. Something like below screenshot.
But I’m running into problems. I’ve tried two approaches
-
Using a
CustomPainter
on a TextSpan to paint the decoration.Problem: Can pair it with other text spans but it doesn’t handle line breaks correctly.
-
Using
background
property on TextStyle withPaint()
and shader. The line breaks work fine here.Problem: This behaves weird when scrolling.
Is there a different approach I can take here? I’d want to keep the line-breaking properties intact while being able to highlight only certain parts of the text. Thanks for your time!
class UnderlineText extends StatelessWidget {
const UnderlineText({super.key});
static const data1 = 'This is un-highlighted text';
static const data2 = ' and this is a very long highlighted text to test if '
'highlight would wrap itself when text folds.';
static const data3 = "Ascent is the font's spacing above the baseline "
"without leading and descent is the spacing below the baseline without "
"leading. Leading is split evenly between the top and bottom. The values "
"for ascent and descent are provided by the font named by fontFamily.";
static const data4 =
" If no fontFamily or fontFamilyFallback is provided, then the platform's "
"default family will be used. Many fonts will have leading values of zero, "
"so in practice, the leading component is often irrelevant.";
@override
Widget build(BuildContext context) {
final font = Theme.of(context).textTheme.headlineMedium;
final fontSize =
(Theme.of(context).textTheme.headlineMedium?.fontSize ?? 0) *
(Theme.of(context).textTheme.headlineMedium?.height ?? 1);
return RichText(
text: TextSpan(
style: font,
children: [
TextSpan(text: data1),
TextSpan(
text: data2 + data3,
style: TextStyle(
background: Paint()
..shader = LinearGradient(
colors: <Color>[
Colors.transparent,
Colors.red,
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
tileMode: TileMode.repeated,
stops: [0.75, 0.75],
).createShader(
Rect.fromLTWH(
0,
0,
0,
fontSize,
),
),
),
),
TextSpan(text: data4),
],
),
);
}
}