// 当前笔画实时 Painter — 绘制正在绘制中的笔画 // // 接收可变点缓冲区的直接引用 + 版本号驱动重绘。 // 每帧仅计算当前笔画的轮廓路径,不影响已完成笔画层。 // isComplete: false 让 perfect_freehand 对实时笔尖做端点平滑。 import 'package:flutter/widgets.dart'; import 'stroke_model.dart'; import 'stroke_renderer.dart'; /// 当前笔画实时 Painter /// /// 由 ListenableBuilder 包裹,监听 ValueNotifier _strokeVersion。 /// 每次 pointer move 递增 version,触发此 Painter 重绘。 /// 仅渲染当前正在绘制的笔画,已完成笔画由 CachedStrokesPainter 处理。 class ActiveStrokePainter extends CustomPainter { /// 当前笔画的采样点(直接引用可变缓冲区,不拷贝) final List points; /// 画笔类型 final BrushType brushType; /// 画笔颜色(CSS 十六进制) final String color; /// 画笔宽度 final double width; /// 版本号,每次 pointer move 递增 final int version; ActiveStrokePainter({ required this.points, required this.brushType, required this.color, required this.width, required this.version, }); @override void paint(Canvas canvas, Size size) { if (points.length < 2) return; // isComplete: false — 实时笔尖不做端点封口,视觉更自然 final outlinePoints = pointsToOutline( points, brushType, width, isComplete: false, ); if (outlinePoints.isEmpty) return; final path = buildStrokePath(outlinePoints); // 橡皮擦实时反馈:绘制半透明灰色,让用户看到擦除范围 // 实际擦除在笔画完成后的合成图中通过 BlendMode.dstOut 执行 if (brushType == BrushType.eraser) { canvas.drawPath(path, Paint() ..color = const Color(0x40808080) // 25% 灰色 ..style = PaintingStyle.fill ..isAntiAlias = true); return; } // 构造临时 Stroke 用于获取 Paint final stroke = Stroke( id: '__active__', points: points, brushType: brushType, color: color, width: width, ); final paint = createPaintForStroke(stroke); canvas.drawPath(path, paint); } @override bool shouldRepaint(covariant ActiveStrokePainter oldDelegate) { return oldDelegate.version != version; } }