前言
今天看下Flutter中关于绘图相关的部件,这里主要用到的有:
CustomPaint()
CustomPaint({
this.painter,
this.foregroundPainter,
this.size = Size.zero,
this.isComplex = false,
this.willChange = false,
Widget child,
})
}
内部需要接受一个painter
,是CustomPainter
类型,这里我们需要继承并创建一个CustomPainter
子类,并传给painter
,这里我创建了_BackDrawPainter
子类,并重写了void paint(Canvas canvas, Size size)
方式,这个方式是绘制的核心;当需要绘制的时候会触发paint()
方法;shouldRepaint ()
会在绘制前触发,这里可以通过一些逻辑判断来控制是否需要执行一次绘制;
class _BackDrawPainter extends CustomPainter {
List<Path> linePaths;
int drawType;
_BackDrawPainter(this.linePaths, {this.drawType});
int linesCount;
@override
void paint(Canvas canvas, Size size) {
// print('_BackDrawPainter draw......');
var custompPaint = Paint()
..style = PaintingStyle.stroke
..color = Colors.black
..isAntiAlias = true
..strokeJoin = StrokeJoin.round
..strokeCap = StrokeCap.round
..strokeWidth = 2.0;
for (int i = 0; i < linePaths.length; i++) {
Path path = linePaths[i];
canvas.drawPath(path, custompPaint);
}
}
@override
bool shouldRepaint(_BackDrawPainter oldDelegate) {
return oldDelegate.linePaths.length != this.linePaths.length;
}
}
同时我也给foregroundPainter
,配置了CustomPainter
,这里主要维护实时绘制时的处理:
class _RealDrawPainter extends CustomPainter {
Path realPath;
int realDrawType;
_RealDrawPainter(this.realPath, {this.realDrawType});
@override
void paint(Canvas canvas, Size size) {
// print('_RealDrawPainter draw...... $realPath');
if (realPath != null) {
// print('内部=>_RealDrawPainter draw...... $realPath');
var paint = Paint()
..style = PaintingStyle.stroke //填充
..color = Colors.black
..strokeJoin = StrokeJoin.round
..strokeCap = StrokeCap.round
// ..blendMode = BlendMode.colorDodge
..isAntiAlias = true
..strokeWidth = 2.0;
canvas.drawPath(realPath, paint);
}
}
@override
bool shouldRepaint(_RealDrawPainter oldDelegate) {
return realPath != null;
}
}
其它的就是绘制部分了,通过GestureDetector()
来接收并处理事件:
@override
Widget build(BuildContext context) {
return Stack(
children: [
GestureDetector(
onPanDown: (DragDownDetails details) {
_currentPath = Path();
if(_drawType == 0){//一般曲线
_currentPath = Path.from(_currentPath)
..moveTo(details.localPosition.dx, details.localPosition.dy);
}else if(_drawType == 1){//矩形
_currentPath = Path.from(_currentPath)..addRect(Rect.fromPoints(details.localPosition, details.localPosition));
}else if(_drawType == 2){//内切圆
_currentPath = Path.from(_currentPath)..addOval(Rect.fromPoints(details.localPosition, details.localPosition));
}else if(_drawType == 3){//正圆
_currentPath = Path.from(_currentPath)..addArc(Rect.fromCircle(center: details.localPosition,radius: 0.0), 0, 2.0 * pi);
}
_startPoint = details.localPosition;
setState(() {});
},
onPanUpdate: (DragUpdateDetails details) {
if(_drawType == 0){//一般曲线
_currentPath = Path.from(_currentPath)
..lineTo(details.localPosition.dx, details.localPosition.dy);
}else if(_drawType == 1){//矩形
_currentPath.reset();
_currentPath = Path.from(_currentPath)..addRect(Rect.fromPoints(_startPoint, details.localPosition));
}else if(_drawType == 2){//内切圆
_currentPath.reset();
_currentPath = Path.from(_currentPath)..addOval(Rect.fromPoints(_startPoint, details.localPosition));
}else if(_drawType == 3){//正圆
_currentPath.reset();
Rect frame = Rect.fromPoints(_startPoint, details.localPosition);
double radius = sqrt(pow(frame.width,2) * pow(frame.height,2));
print('radius:$radius');
_currentPath = Path.from(_currentPath)..addArc(Rect.fromCircle(center: _startPoint,radius: radius*0.5), 0, 2.0 * pi);
}
setState(() {});
},
onPanEnd: (DragEndDetails details) {
print('onPanEnd');
linePathArray = List.from(linePathArray)..add(_currentPath);
setState(() {});
_currentPath = null;
},
child: ClipRect(
child: Container(
child: CustomPaint(
painter: _BackDrawPainter(linePathArray,drawType: _drawType),
foregroundPainter: _RealDrawPainter(_currentPath,realDrawType: _drawType),
isComplex: true,
willChange: true,
child: Container(),
),
),
)
),
Positioned(
width: 700,
height: 40,
bottom: 0,
child: Container(
// color: Colors.red,
child: Row(
children: _getButtons(),
),
)
)
],
);
}
问题
-
shouldRepaint()
并并不是我理解的方式来控制绘制的,有待研究
我想要的效果是当我在foregroundPainter
实时绘制时,painter
不要触发绘制,当foregroundPainter
结束后执行一次painter
绘制,但绘制时需要setState()
,这样两个painter都会执行,而且在painter
的shouldRepaint ()
中无论返回true
orfalse
都会发生绘制,问题? - 性能有待考量
总结
参考文献:https://book.flutterchina.club/chapter10/custom_paint.html
网友评论