Flutter 2:带有 TextPainter 的渐变文本在列中中断

Flutter 2: Gradient Text with TextPainter breaking in Column

我遇到了我的个人 GradientText 问题,它不使用 ShaderMask。

这里是我使用的设备:

我是这样称呼它的:

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
      ),
    ),
  ],
)

这里是我的小部件的代码:

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

这里给出了这个结果:

而它应该给出这个结果:

所以我不明白为什么它不显示整个文本,我不明白为什么当我将 'Party Lo' 作为文本参数传递时它显示它。

而且我也不明白为什么当我将 maxLines 更改为 2 时,它会把它放在我的第一行下面,而已经有这么多 space 可用

有人可以帮助解决这些问题吗?

这是我想要的结果:

我稍微简化了你的 _GradientTextPainter 并且还添加了可选的 alignment 属性 到 GradientText - 如果传入的大小限制没有限制(宽度或高度是未设置)然后它需要最小的固有大小来绘制自己,否则 alignment 用于在大小的父窗口小部件内对齐 GradientText

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