0

I am encouterring problem with my personal GradientText which is made to do not use ShaderMask.

Here the device I use:

enter image description here

I call it like that:

Column(
  children: [
    GradientText(
      'Party Lopes',
      const LinearGradient(
        colors: <Color>[
          Color.fromARGB(255, 227, 82, 0),
          Color.fromARGB(255, 244, 176, 0)
        ],
        begin: Alignment.topLeft,
        end: Alignment.bottomRight,
      ),
      style: TextStyle(
          fontWeight: FontWeight.w500
      ),
    ),
  ],
)

And here the code of my Widget:

import 'package:flutter/material.dart';

class GradientText extends StatelessWidget {
  final String text;
  final TextStyle style;
  final Gradient? gradient;
  final int? maxLine;

  const GradientText(
    this.text,
    {
      @required this.gradient,
      this.style = const TextStyle(),
      this.maxLine = 1,
      Key? key,
    }
    ) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final TextPainter _painter = TextPainter(
      maxLines: maxLine,
      textDirection: TextDirection.rtl,
      text: TextSpan(
        text: text,
        style: style
      ),
    );
    _painter.layout();

    print(_painter.size);

    return CustomPaint(
      size: _painter.size,
      painter: _GradientTextPainter(
        text: text,
        style: style,
        gradient: gradient,
        maxLine: maxLine
      ),
    );
  }
}

class _GradientTextPainter extends CustomPainter {
  final Gradient? gradient;
  final String? text;
  final TextStyle? style;
  final int? maxLine;

  _GradientTextPainter({
    Listenable? repaint,
    @required this.text,
    @required this.style,
    @required this.gradient,
    @required this.maxLine,
  }) : super(repaint: repaint);

  @override
  void paint(Canvas canvas, Size size) {
    final Paint _gradientShaderPaint = Paint()
      ..shader = gradient != null ?
      gradient!.createShader(
        Offset.zero & size
      ) :
      null;

    final TextPainter _textPainter = TextPainter(
        maxLines: maxLine,
        textDirection: TextDirection.ltr,
        text: TextSpan(
          text: text!,
          style: TextStyle(
            foreground: _gradientShaderPaint,
            fontSize: style!.fontSize,
            fontWeight: style!.fontWeight,
            height: style!.height,
            decoration: style!.decoration,
            decorationColor: style!.decorationColor,
            decorationStyle: style!.decorationStyle,
            fontStyle: style!.fontStyle,
            letterSpacing: style!.letterSpacing,
            fontFamily: style!.fontFamily,
            locale: style!.locale,
            textBaseline: style!.textBaseline,
            wordSpacing: style!.wordSpacing,
          ),
        )
    );
    _textPainter.layout(
      minWidth: 0,
      maxWidth: size.width,
    );
    _textPainter.paint(
      canvas,
      Offset(
        (size.width - _textPainter.width) / 2,
        (size.height - _textPainter.height) / 2
      )
    );
  }

  @override
  bool shouldRepaint(_GradientTextPainter oldDelegate) {
    return gradient != oldDelegate.gradient || text != oldDelegate.text ||
    style != oldDelegate.style;
  }
}

And here it gives this result :

enter image description here

Whereas it should give this result:

enter image description here

So I don't understand why it doesn't display the entire text, and I don't understand why when I pass 'Party Lo' as a text parameter it displays it.

enter image description here

And also I don't understand why when I change the maxLines to 2 for example it place it under my first line whereas there is so much space already available

enter image description here

Can somebody please provide help fixing these problems ?

Here the result I am trying to have:

enter image description here

Da2ny
  • 897
  • 2
  • 9
  • 24

1 Answers1

0

i simplified your _GradientTextPainter a little bit and also added optional alignment property to GradientText - if incoming size constraints are not bounded (either width or height is not set) then it takes the minimum intrinsic size to draw itself, otherwise alignment is used to align GradientText within sized parent widget:

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

class GradientText extends StatelessWidget {
  final String text;
  final TextStyle style;
  final Gradient gradient;
  final int maxLines;
  final Alignment alignment;
  final String ellipsis;

  const GradientText(
    this.text,
    this.gradient,
    {
      this.style = const TextStyle(),
      this.maxLines = 1,
      this.alignment = Alignment.centerLeft,
      this.ellipsis = '\u2026',
      Key? key,
    }
  ) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        final TextPainter textPainter = TextPainter(
          maxLines: maxLines,
          textDirection: TextDirection.ltr,
          text: TextSpan(
            text: text,
            style: style,
          ),
          ellipsis: ellipsis,
        );
        textPainter.layout(
          maxWidth: constraints.maxWidth,
        );
        final bounded = constraints.hasBoundedHeight &&
            constraints.hasBoundedWidth;
        final size = bounded? constraints.biggest : textPainter.size;
        // print('constraints.biggest: ${constraints.biggest},
        // textPainter.size: ${textPainter.size}');
        // print('incoming constraints are ${bounded? "" : "NOT "}bounded,
        // using ${bounded? "constraint\'s" : "text"} size: $size');

        return CustomPaint(
          painter: _GradientTextPainter(
            text: text,
            style: style,
            gradient: gradient,
            textPainter: textPainter,
            alignment: alignment,
          ),
          size: size,
        );
      }
    );
  }
}

class _GradientTextPainter extends CustomPainter {
  final Gradient gradient;
  final String text;
  final TextStyle style;
  final TextPainter textPainter;
  final Alignment alignment;

  _GradientTextPainter({
    Listenable? repaint,
    required this.text,
    required this.style,
    required this.gradient,
    required this.textPainter,
    required this.alignment,
  }) : super(repaint: repaint);

  @override
  void paint(Canvas canvas, Size size) {
    final textSpanRect = alignment.inscribe(
      textPainter.size,
      Offset.zero & size
    );
    // print('=== $size * $alignment => $textSpanRect');

    if (debugPaintSizeEnabled)
      debugPaintPadding(canvas, textSpanRect, textSpanRect.deflate(2));

    textPainter.text = TextSpan(
      text: text,
      style: style.copyWith(
        foreground: Paint()..shader = gradient.createShader(textSpanRect),
      ),
    );
    textPainter.layout(
      minWidth: 0,
      maxWidth: size.width,
    );
    textPainter.paint(canvas, textSpanRect.topLeft);
  }

  @override
  bool shouldRepaint(_GradientTextPainter oldDelegate) {
    return gradient != oldDelegate.gradient || text != oldDelegate.text ||
    style != oldDelegate.style;
  }
}
Da2ny
  • 897
  • 2
  • 9
  • 24
pskink
  • 23,874
  • 6
  • 66
  • 77
  • It works but only with Expanded, when I remove it there is a RenderFlex overflowed by Infinity pixels – Da2ny Oct 16 '21 at 09:25
  • I have updated the question so you will see my current use of it. I have tried to change your SizedBox.expand() by SizedBox.shrink() but it doesn't works too. – Da2ny Oct 16 '21 at 09:57
  • yes but if I wrap it in a `SizedBox` it depends only of it so it will just be a pain to use it. Sometime I will not known the Size I need so I can't. What I would like, is to do the same GradientText with a ShaderMask but without the ShaderMask and I can't figure it out. – Da2ny Oct 16 '21 at 10:14
  • sorry I hadn't got the possibility to answer you before. Thank you for your help, it works great but I guess the only thing missing is textoverflow that isn't working when I put it in the textstyle. So if I set only one line a part of the text which overflow just isn't rendered. – Da2ny Oct 18 '21 at 12:29
  • add `ellipsis: '\u2026'` (or any other string you like) when creating `TextPainter` - i mean inside `final TextPainter textPainter = TextPainter(...` – pskink Oct 18 '21 at 12:50
  • Thank you it works perectly ! I'll look at it in more detail to understand all of what you made, it is insane ! – Da2ny Oct 18 '21 at 13:09
  • sure, your welcome, i left two `print()`s to be more verbose what size the widget takes – pskink Oct 18 '21 at 13:14
  • Yes I have seen that from what I have read it came from the size which wasn't the correct one right ? By the way I'll just modify you response with the code I have modified (there is a if which doesn't work due to an uninitialized variable, and I commented prints) – Da2ny Oct 18 '21 at 13:17
  • what `if`? this one: `if (debugPaintSizeEnabled) debugPaintPadding(canvas, textSpanRect, textSpanRect.deflate(2));`? – pskink Oct 18 '21 at 13:18
  • Yes this one, I have sent the modification – Da2ny Oct 18 '21 at 13:19
  • `import 'package:flutter/rendering.dart';` it is used for "visual debugging" - more https://flutter.dev/docs/testing/code-debugging#debug-flags-layout – pskink Oct 18 '21 at 13:20
  • oh ok thank you I don't know this package sorry :/ – Da2ny Oct 18 '21 at 13:20
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/238277/discussion-between-da2ny-and-pskink). – Da2ny Oct 18 '21 at 14:16