当Flutter提供的现有Widget⽆法满⾜我们的需求,或者我们为了共享代码需要封装⼀些通⽤Widget,这时我们就需要⾃ 定义Widget。
在Flutter中⾃定义Widget有三种⽅式:通过组合其它Widget、⾃绘和实现RenderObject
组合其它Widget
这种⽅式是通过拼装其它低级别的Widget来组合成⼀个⾼级别的Widget,例如我们之前介绍的Container就是⼀个组合 Widget,它是由DecoratedBox、ConstrainedBox、Transform、Padding、Align等组成。
在Flutter中,组合的思想⾮常重要,Flutter提供了⾮常多的基础Widget,⽽我们的界⾯开发都是按照需要组合这些 Widget来实现各种不同的布局。
⾃绘
如果遇到⽆法通过系统提供的现有Widget实现的UI时,如我们需要⼀个渐变圆形进度条,⽽Flutter提供的 CircularProgressIndicator并不⽀持在显示精确进度时对进度条应⽤渐变⾊(其valueColor属性只⽀持执⾏旋转动画时 变化Indicator的颜⾊),这时最好的⽅法就是通过⾃定义Widget绘制逻辑来画出我们期望的外观。Flutter中提供了 CustomPaint和Canvas供我们⾃绘UI外观。
实现RenderObject
Flutter提供的任何具有UI外观的Widget,如⽂本Text、Image都是通过相应的RenderObject渲染出来的,如Text是由 RenderParagraph渲染,⽽Image是由RenderImage渲染。RenderObject是⼀个抽象类,它定义了⼀个抽象⽅ 法 paint(...) :
void paint(PaintingContext context, Offset offset)
PaintingContext代表Widget的绘制上下⽂,通过PaintingContext.canvas可以获得Canvas,绘制逻辑主要是通过 Canvas API来实现。⼦类需要实现此⽅法以实现⾃身的绘制逻辑,如RenderParagraph需要实现⽂本绘制逻辑,⽽ RenderImage需要实现图⽚绘制逻辑。
可以发现,RenderObject中最终也是通过Canvas来绘制的,那么通过实现RenderObject的⽅式和上⾯介绍的通过 CustomPaint和Canvas⾃绘的⽅式有什么区别?
CustomPaint只是为了⽅便开发者封装的⼀个代理 类,它直接继承⾃SingleChildRenderObjectWidget,通过RenderCustomPaint的paint⽅法将Canvas和画笔Painter连接起来实现了最终的绘制(绘制逻辑在Painter中)。
总结
组合是⾃定义组件最简单的⽅法,在任何需要⾃定义的场景下,都应该优先考虑是否能够通过组合来实现。⽽⾃绘和通 过实现RenderObject的⽅法本质上是⼀样的,都需要开发者调⽤Canvas API⼿动去绘制UI,缺点时必须了解Canvas API,并且得⾃⼰去实现绘制逻辑,⽽优点是强⼤灵活,理论上可以实现任何外观的UI
网友评论