我需要使用自定义绘画工具在ListTile中渲染我的自定义对象,以便绘制一些自定义文本。
ListTile(
title: CustomPaint(
painter: RowPainter.name(_titleFontSelected, _titleFont, text, index, MediaQuery.of(context), currentRow),
),
),
在我的RowPainter内部,用选定的字体绘制文本。 当行太大时,它会自动换行并在给定的绘画尺寸之外进行绘制。
void paint(Canvas canvas, Size size) {
我喜欢这种行为,但是如何调整绘画区域的高度呢?因为这是一个问题,因为它与下一个列表行重叠。
我知道CustomPaint
具有可设置的属性Size
,但我只知道使用TextPainter getBoxesForSelection
的绘画函数内部的文本尺寸,但为时已晚。
如果文本自动换行,如何动态“调整”行高?
答案 0 :(得分:2)
您无法动态调整自定义绘画工具的大小,但是,您的问题 可以使用CustomPaint
来解决。
我将首先详细介绍动态大小调整,然后说明如何使用固定大小解决此问题。
这实际上是CustomPaint
有其限制的地方,因为它没有为您提供一种根据内容调整画家大小的方法。
执行此操作的正确方法是实现自己的RenderBox
并重写performLayout
以根据内容调整渲染对象的大小。
RenderBox
documentation对此非常详细,但是,由于它与构建窗口小部件完全不同,因此您可能仍然难以进入。
您不需要上述所有 ,因为您的自定义绘画没有child
。
您只需将size
parameter提供给CustomPaint
,然后在父窗口小部件中计算所需的高度。
您可以使用LayoutBuilder
来获取可用宽度:
LayoutBuilder(
builder: (context, constraints) {
final maxWidth = constraints.maxWidth;
...
}
)
现在,您甚至可以在输入自定义绘画之前使用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,
...
);
}
现在,您甚至可以直接将textPainter
传递给自定义绘画工具,而不必传递样式参数。
您的逻辑可能会更复杂一些,但是要点是,您可以在创建CustomPaint
之前计算大小,这可以设置大小。
如果您需要更复杂的内容,则可能必须实现自己的RenderBox
。
答案 1 :(得分:0)
我还没有测试过,但这可能有用:
首先,将CustomPaint
包装到有状态的小部件(例如DynamicCustomPaint
)中,以动态地操作您的小部件。
您为CustomPainter
提供了一个功能onResize
,当您知道它时,它将为您提供新的画布大小。
一旦知道画布的确切尺寸,就可以调用此函数。例如,使用this technique时,您无需绘制文本即可知道其大小。
将调用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;
}
答案 2 :(得分:0)
改用 SingleChildRenderObjectWidget
和 RenderBox
。带有动态调整大小的完整简单示例。
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Scaffold(
body: Center(
child: Column(
children: [
SizedBox(height: 100,),
Text('I am above'),
MyWidget(),
Text('I am below')
],
),
),
),
));
}
class MyWidget extends SingleChildRenderObjectWidget {
@override
MyRenderBox createRenderObject(BuildContext context) {
return MyRenderBox();
}
}
class MyRenderBox extends RenderBox {
double myHeight = 200;
@override
void paint(PaintingContext context, Offset offset) {
Paint paint = Paint()
..color = Colors.black..style = PaintingStyle.fill;
context.canvas.drawRect(
Rect.fromLTRB(offset.dx, offset.dy,
offset.dx + size.width, offset.dy + size.height,), paint);
}
@override
void performLayout() {
size = Size(
constraints.constrainWidth(200),
constraints.constrainHeight(myHeight),
);
}
// Timer just an example to show dynamic behavior
MyRenderBox(){
Timer.periodic(Duration(seconds: 2), handleTimeout);
}
void handleTimeout(timer) {
myHeight += 40;
markNeedsLayoutForSizedByParentChange();
layout(constraints);
}
}
CustomPainter 只会调整到它的孩子的大小或传递给构造函数的初始值。 Documentation:
<块引用>定制画家通常会根据他们的孩子调整自己的尺寸。如果他们没有孩子,他们会尝试调整自己的大小,默认为 Size.zero。大小不能为空。
RenderBox 基础