Flutter---简单画板应用

📅 发布时间:2026/7/4 18:35:29 👁️ 浏览次数:
Flutter---简单画板应用
效果图实现逻辑1.二维列表存储多笔画一维列表存储当前笔画 2.Listener手势监听 3.创建绘画类数据存储结构// 二维列表存储多笔画 ListListOffset strokes []; // 所有完成的笔画 // 例如strokes [ // [p1, p2, p3, ...], // 第一笔 // [p4, p5, p6, ...], // 第二笔 // [p7, p8, p9, ...] // 第三笔 // ] // 一维列表存储当前笔画 ListOffset? currentStroke; // 正在画的笔画Listener手势监听Listener( onPointerDown: (event) { ... }, // 手指按下 onPointerMove: (event) { ... }, // 手指移动 onPointerUp: (event) { ... }, // 手指抬起 )完整的状态变化示例// 初始状态 strokes [] // 空画板 currentStroke null // 没有正在画的笔画 // 第一笔按下 currentStroke [p1] // 记录起点 // 第一笔移动 currentStroke [p1, p2] // 添加点 currentStroke [p1, p2, p3] // 继续添加 // 第一笔抬起 strokes [[p1, p2, p3]] // 保存到历史 currentStroke null // 清空当前 // 第二笔按下 currentStroke [p4] // 新的一笔 // 最终状态 strokes [ // 两笔画 [p1, p2, p3], // 第一笔 [p4, p5, p6] // 第二笔 ]绘制原理图解点列表[p1, p2, p3, p4, p5] 绘制过程 p1 —— p2 —— p3 —— p4 —— p5 ① ② ③ ④ 画线①p1到p2 画线②p2到p3 画线③p3到p4 画线④p4到p5执行流程用户触摸屏幕 → onPointerDown 触发 创建新笔画 → 初始化 currentStroke 手指移动 → onPointerMove 连续触发添加点 实时显示 → 每次 setState 触发 CustomPaint 重绘 手指抬起 → onPointerUp 触发保存笔画 点击清除 → 清空所有数据重置画板代码实例import package:flutter/gestures.dart; import package:flutter/material.dart; class HomePage extends StatefulWidget { const HomePage({super.key}); override StateStatefulWidget createState() _HomePageState(); } class _HomePageState extends StateHomePage { // 存储多个笔画每个笔画是一个点列表 ListListOffset strokes []; // 当前正在绘制的笔画 ListOffset? currentStroke; override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text(画板), actions: [ //清除按钮 IconButton( icon: const Icon(Icons.clear), onPressed: () { setState(() { strokes.clear(); currentStroke null; }); }, ), ], ), body: Center( child: Listener( onPointerDown: (event) { setState(() { // 开始新的一笔 currentStroke [event.localPosition]; }); }, onPointerMove: (event) { setState(() { // 添加到当前笔画 currentStroke?.add(event.localPosition); }); }, onPointerUp: (event) { setState(() { // 完成当前笔画添加到笔画列表 if (currentStroke ! null currentStroke!.length 1) { strokes.add(currentStroke!); } currentStroke null; }); }, child: Container( //画板 width: 300, height: 300, color: Colors.grey[200], child: CustomPaint( painter: DrawingPainter( strokes: strokes, currentStroke: currentStroke, ), ), ), ), ), ); } } class DrawingPainter extends CustomPainter { final ListListOffset strokes; // 所有完成的笔画 final ListOffset? currentStroke; // 当前正在画的笔画 DrawingPainter({required this.strokes, this.currentStroke}); override void paint(Canvas canvas, Size size) { //配置画笔 final paint Paint() ..color Colors.black ..strokeWidth 3.0 ..strokeCap StrokeCap.round //圆头端点 ..style PaintingStyle.stroke; // 绘制所有已完成的笔画 for (var stroke in strokes) { _drawStroke(canvas, stroke, paint); } // 绘制当前笔画如果有 if (currentStroke ! null) { _drawStroke(canvas, currentStroke!, paint); } } void _drawStroke(Canvas canvas, ListOffset stroke, Paint paint) { if (stroke.isEmpty) return; //情况1一个点画一个点 if (stroke.length 1) { canvas.drawCircle(stroke.first, 2, paint); //参数圆心位置、圆半径、画笔样式 return; } // 情况2绘制线条 for (int i 0; i stroke.length - 1; i) { //把笔画中的相邻点两两连接起来形成连续的线条 canvas.drawLine(stroke[i], stroke[i 1], paint);//参数点1点2画笔样式 } } override bool shouldRepaint(covariant DrawingPainter oldDelegate) { return oldDelegate.strokes ! strokes || oldDelegate.currentStroke ! currentStroke; } }