Flutter:如何实现CustomPainter组件的垂直(高度)方向扩展
我用CustomPainter实现了一个自定义组件,但把它放到Column里时,怎么都没法让它扩展高度。之前看过相关问题,尝试用CrossAxisAlignment.stretch也没解决;换成Expanded组件的话,还出现了编译错误,底部的卡片文本直接绘制在了CustomPaint组件的上方。
我的CardView组件继承自CustomPaint,没有子组件,所有内容都是通过CustomPainter的paint(canvas, size)方法在画布上绘制的。我在这个方法里打印size.height,结果居然是0.0,这也能解释为什么底部文本会覆盖组件了。
组件代码如下:
class CardViewState extends State<CardView> { @override Widget build(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.stretch, children: <Widget>[ new Padding( padding: new EdgeInsets.all(10.0), child: new Text( "CARD TOP", //widget.card.name, style: new TextStyle( fontSize: 25.0, color: Colors.black, fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), ), new Flexible( child: new CustomPaint( painter: new CardPainter(widget.card, widget.numbers), ), ), new Padding( padding: new EdgeInsets.all(20.0), child: new Text( "CARD BOTTOM", style: new TextStyle( fontSize: 25.0, color: Colors.black, fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), ), ], ); } }
目前的效果是底部文本与CustomPaint区域重叠,CustomPaint完全没有获取到应有的高度空间。
其实核心问题在于CustomPaint默认不会主动去占据可用空间,如果它没有子组件,就会默认使用最小尺寸(也就是0高度),这就是你打印size.height为0的原因。咱们可以通过以下几步解决:
1. 用Expanded替代Flexible,分配剩余空间
Flexible只是让组件可以伸缩,但不会强制占据剩余空间;而Expanded会强制占据Column中除了其他固定尺寸组件之外的所有剩余空间,这正是我们需要的。
2. 让CustomPaint获取到正确的尺寸
因为你的CustomPaint没有子组件,所以需要主动告诉它该占据多大的空间,有两种简单的方式:
方式一:添加SizedBox.expand()作为child
给CustomPaint加一个SizedBox.expand()子组件,它会自动填充Expanded分配的所有空间,CustomPaint就会继承这个尺寸:
Expanded( child: CustomPaint( painter: CardPainter(widget.card, widget.numbers), child: SizedBox.expand(), // 关键:让CustomPaint获取到可用空间的尺寸 ), ),
方式二:用LayoutBuilder传递约束
通过LayoutBuilder获取父组件(也就是Expanded)的约束,然后直接给CustomPaint设置size:
Expanded( child: LayoutBuilder( builder: (context, constraints) { return CustomPaint( size: constraints.biggest, // 使用父组件的最大可用尺寸 painter: CardPainter(widget.card, widget.numbers), ); }, ), ),
3. 确保绘制逻辑使用正确的size
最后要确认你的CardPainter的paint方法里,是基于传入的size参数来绘制内容的,而不是使用固定尺寸。这样当size正确后,你的自定义内容就会在分配的空间里正常绘制,底部的文本也不会再重叠了。
内容的提问来源于stack exchange,提问作者duduf

