Flutter如何通过CustomPaint实现拖拽绘制图形功能
Flutter 白板拖拽绘制规则图形实现
这个功能逻辑和你之前写的自由画线不一样,不需要记录拖拽路径上的所有点位,只要记住拖拽动作的起点、实时移动的终点,两个点就能确定图形的位置和尺寸,按下面的步骤写就能做出你截图里的拖拽预览、松手落图的效果:
先定义好需要的状态变量
在绘制页的State里存这几个值就行:- 当前选中的工具类型(自由线/矩形/圆形/箭头等,用枚举存最方便)
- 拖拽起始点:
Offset? _dragStart - 拖拽实时点位:
Offset? _dragCurrent - 已绘制完成的元素列表:每个元素存清楚类型、起点、终点、画笔参数就行,别直接存渲染好的Path,后面要做选中、缩放、删除的时候会很麻烦。
给GestureDetector绑三个拖拽事件
逻辑非常直接:onPanStart:手指按到屏幕的时候,把当前触点坐标赋值给_dragStart,同时也给_dragCurrent赋同一个值,调setState刷新界面onPanUpdate:手指在屏幕上拖的时候,把最新的触点坐标更新给_dragCurrent,每更新一次就刷一次界面,这时候就能看到图形跟着手指变大小变位置的预览效果onPanEnd:手指抬起来的时候,把_dragStart和_dragCurrent拼起来存成一个正式的图形元素,加到已绘制列表里,然后把两个拖拽点位清空,再刷一次界面就完成落图了。
在CustomPaint里分两层画
重写CustomPainter的paint方法的时候,按顺序画就行:- 先遍历已绘制的元素列表,根据每个元素的类型、起止点,用正常的不透明实边画笔把所有历史内容画出来
- 再判断如果
_dragStart和_dragCurrent都不为空,说明用户正在拖动画图形,这时候用两个点生成外接矩形,拿半透明的预览画笔(也可以做虚线效果)画当前的临时图形,就和你截图里的效果一致了。
画矩形的核心代码就几行:
// 正在拖拽画矩形的时候 if (currentTool == ShapeType.rectangle && _dragStart != null && _dragCurrent != null) { // fromPoints会自动处理四个拖拽方向的点位顺序,不用自己算坐标大小 final rect = Rect.fromPoints(_dragStart!, _dragCurrent!); // 预览画笔可以设成70%透明度,和正式图形做区分 canvas.drawRect(rect, previewPaint); }其他图形逻辑完全一样:椭圆/圆形直接把外接矩形传给
canvas.drawOval(),直线就连两个点,三角形取外接矩形的三个顶点画路径就行。
小提示:如果要加按住快捷键画正圆、正方形的功能,只要在onPanUpdate里判断按键状态,把_dragCurrent的坐标做等比修正再赋值就行,不用改其他逻辑。
实现效果参考:
内容的提问来源于stack exchange,提问作者Kevin Yang
相关产品推荐
相关产品推荐

