一、如何使用Canvas draw/paint
在Android中,您可以使用Canvas在屏幕上绘制自定义形状。但是在Flutter我们要借助CustomPaint和CustomPainter类来帮助我们绘制画布,它们实现您的算法以绘制各种图案到画布。
二、CustomPaint和CustomPainter
1、CustomPaint 介绍
CustomPaint让用户能够自定义widget,它提供了canvas用户可以通过这个canvas来绘制widget,CustomPaint会先调用painter绘制背景,然后再绘制child,最后调用foregroundPainter来绘制前景,CustomPaint的定义如下
const CustomPaint({
Key key,
this.painter,
this.foregroundPainter,
this.size = Size.zero,
this.isComplex = false,
this.willChange = false,
Widget child,
})
painter
:负责绘制背景的painterforegroundPainter
: 负责绘制前景的paintersize
: 控件大小isComplex
: 是否复杂绘制,需要用cache来提高绘制效率willChange
: 和isComplex配合使用,当启用缓存时,该属性代表在下一帧中绘制是否会改变child
: 子widget
2、CustomPainter 介绍
CustomPaint的绘制过程都将会交给CustomPainter来完成,CustomPainter是个抽象类,初始化CustomPainter的时候必须要重写它的paint
跟 shouldRepaint
接口,可以根据自己的场景来选择重写hitTest
跟shouldRebuildSemantics
方法。
paint
: 每当CustomPaint需要重绘的时候都会调用此接口shouldRepaint
: 当CustomPaint被重新设置了一个新的painter后会回调此方法,CustomPaint会根据shouldRepaint的返回值来判断是否需要重新绘制ui,譬如新的painter跟旧的painter绘制的内容不一样时,此时shouldRepaint需要返回true来通知CustomPaint重新绘制。
3、Canvas 介绍
提供图形操作界面,canvas提供了各种绘制接口来绘制图形。真正的绘制是由canvas跟paint来完成的
//画圆
drawCircle(Offset c, double radius, Paint paint) → void
//画图片
drawImage(Image image, Offset p, Paint paint) → void
//画九宫图
drawImageNine(Image image, Rect center, Rect dst, Paint paint) → void
//画线
drawLine(Offset p1, Offset p2, Paint paint) → void
//画椭圆
drawOval(Rect rect, Paint paint) → void
//画文字
drawParagraph(Paragraph paragraph, Offset offset) → void
//画Rect区域
drawRect(Rect rect, Paint paint) → void
//画阴影
drawShadow(Path path, Color color, double elevation, bool transparentOccluder) → void
4、Paint
在canvas上绘制时要使用的画笔。
color
: 设置画笔颜色isAntiAlias
: 设置画笔是否扛锯齿shader
: 着色器,填充形状或者画线时用到,如果没设置将会使用colorstrokeWidth
: 设置画笔画线宽度style
:绘制模式,画线或充满
三、下面是对CustomPainter的使用
class Signature extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return new SignatureState();
}
}
class SignatureState extends State<Signature> {
List<Offset> _points = <Offset>[];
Widget build(BuildContext context) {
return new GestureDetector(
onPanUpdate: (DragUpdateDetails details) {
setState(() {
RenderBox referenceBox = context.findRenderObject();
Offset localPosition = referenceBox.globalToLocal(details.globalPosition);
var dy = localPosition.dy;
var dx = localPosition.dx;
var width = referenceBox.size.width;
var height = referenceBox.size.height;
if(0<= dx && dx <= width && 0<= dy && dy<=height){
_points = new List.from(_points)..add(localPosition);
}
//如果不添加判断,则会在全局范围内绘制
// _points = new List.from(_points)..add(localPosition);
});
},
behavior: HitTestBehavior.translucent,
onPanEnd: (DragEndDetails details) => _points.add(null),
child: new CustomPaint(
painter: new SignaturePainter(_points),
),
);
}
}
class SignaturePainter extends CustomPainter {
final List<Offset> points;
SignaturePainter(this.points);
@override
void paint(Canvas canvas, Size size) {
// TODO: implement paint
var paint = new Paint()
..color = Colors.black
..strokeCap = StrokeCap.round
..strokeWidth = 5.0;
for (int i = 0; i < points.length - 1; i++) {
if (points[i] != null && points[i + 1] != null) {
canvas.drawLine(points[i], points[i + 1], paint);
}
}
}
@override
bool shouldRepaint(SignaturePainter oldDelegate) {
// TODO: implement shouldRepaint
return oldDelegate.points != points;
}
}
实现效果: