如何动态调整 CustomPainter 的大小

Psy*_*ari 5 dart flutter flutter-layout

我需要使用自定义画家在 ListTile 内呈现我的自定义对象,以便绘制一些自定义文本。

ListTile(
  title: CustomPaint(
    painter: RowPainter.name(
      _titleFontSelected,
      _titleFont,
      text,
      index,
      MediaQuery.of(context),
      currentRow,
    ),
  ),
);
Run Code Online (Sandbox Code Playgroud)

在我的内部,我RowPainter用选定的字体绘制文本。当行太大时,它会自动换行并绘制到给定的油漆尺寸之外。

void paint(Canvas canvas, Size size)
Run Code Online (Sandbox Code Playgroud)

我喜欢这种行为,但如何调整绘画区域的高度?因为这是一个问题,因为它与下一个 List 行重叠。我知道CustomPaint有一个Size可设置的属性,但我只知道我的绘制函数内的文本尺寸,TextPainter getBoxesForSelection但为时已晚。

如果文本换行,如何动态“调整”行画家的高度?

cre*_*not 10

长话短说

您无法动态调整自定义画家的大小,但是,您的问题可以使用CustomPaint.
我将首先详细说明动态调整大小,然后解释如何使用恒定大小解决此问题。

动态尺寸

这本质上是CustomPaint有其局限性的,因为它没有提供一种方法让您根据内容调整画家的大小。

执行此操作的正确方法是实现您自己的RenderBox并重写performLayout以根据内容调整渲染对象的大小。
文档对此非常详细,但是,您可能仍然会发现很难理解它,因为它与构建小部件有很大不同RenderBox。

尺寸恒定

您的情况不需要以上所有内容,因为您没有child适合您的定制油漆的材料。
您只需向您提供size参数CustomPaint并计算父小部件中所需的高度即可。

您可以使用 aLayoutBuilder来获取可用宽度:

LayoutBuilder(
  builder: (context, constraints) {
    final maxWidth = constraints.maxWidth;
    ...
  }
)
Run Code Online (Sandbox Code Playgroud)

现在,您只需使用 a 即可TextPainter在输入自定义油漆之前检索所需的尺寸:

builder: (context, constraints) {
  ...
  final textPainter = TextPainter(
    text: TextSpan(
      text: 'Your text',
      style: yourTextStyle,
    ),
    textDirection: TextDirection.ltr,
  );
  textPainter.layout(maxWidth: maxWidth); // This will make the size available.

  return CustomPaint(
    size: textPainter.size,
    ...
  );
}
Run Code Online (Sandbox Code Playgroud)

现在,您甚至可以textPainter直接将其传递给自定义画家,而不是传递样式参数。


您的逻辑可能有点复杂,但是,重点是您可以在创建之前计算大小CustomPaint,这允许您设置大小。
如果您需要更复杂的东西,您可能必须实现自己的RenderBox.


Ich*_*sos 1

我还没有测试过,但这可能有效:

首先,您将其包装CustomPaint到一个有状态的小部件(称为eg DynamicCustomPaint)中,以动态地操作您的小部件。

你给你CustomPainter一个函数onResize,当你知道它时,它会给你画布的新大小。

一旦您知道画布的确切大小,就可以调用此函数。例如,通过使用这种技术,您不必绘制文本就知道它的大小。

当onResize调用该函数时,您将获得画布的新大小并setState在DynamicCustomPaint状态中调用。

这可能看起来像这样:

class DynamicCustomPaint extends StatefulWidget {
  @override
  _DynamicCustomPaintState createState() => _DynamicCustomPaintState();
}

class _DynamicCustomPaintState extends State<DynamicCustomPaint> {
  Size canvasSize;

  @override
  Widget build(BuildContext context) {
    // Set inital size, maybe move this to initState function
    if (canvasSize == null) {
      // Decide what makes sense in your use-case as inital size
      canvasSize = MediaQuery.of(context).size;
    }
    return CustomPaint(
      size: canvasSize,
      painter: RowPainter.name(_titleFontSelected, _titleFont, text, index, currentRow, onResize: (size) {
        setState(() {
          canvasSize = size;
        });
      }),
    );
  }
}

typedef OnResize = void Function(Size size);

class RowPainter extends CustomPainter {
  RowPainter.name(
    this._titleFontSelected,
    this._titleFont,
    this.text,
    this.index,
    this.currentRow,
    { this.onResize },
  );

  final FontStyle _titleFontSelected;
  final FontStyle _titleFont;
  final String text;
  final int index;
  final int currentRow;
  final OnResize onResize;

  @override
  void paint(Canvas canvas, Size size) {
    // TODO: implement paint

    // call onResize somewhere in here
    // onResize(newSize);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => false;
}
Run Code Online (Sandbox Code Playgroud)