Files
nj/app/lib/features/editor/widgets/active_stroke_painter.dart
iven 9fce34f4ef
Some checks failed
Main Merge / backend (push) Has been cancelled
Main Merge / frontend (push) Has been cancelled
fix(app): 修复 4 个 Flutter 交互问题
1. 首页数据不刷新 — JournalRepository 添加 onJournalChanged
   Stream 变更通知,HomeBloc 订阅后自动刷新
2. 画笔再次点击不弹出面板 — 添加 ToolReactivated 事件,
   工具栏检测已激活工具时发出重新激活信号
3. 钢笔铅笔效果一样 — 调整 perfect_freehand 参数
   (pen: size 10/smooth 0.65, pencil: size 3/smooth 0.35)
4. 橡皮擦不生效 — ActiveStrokePainter 橡皮擦模式绘制
   半透明灰色反馈,笔画完成后 setState 触发 Layer 1 重绘
5. 贴纸文字无法缩放 — DraggableElement 用 Scale 手势
   替换 Pan 手势,支持双指缩放和旋转
2026-06-04 00:05:22 +08:00

83 lines
2.3 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 当前笔画实时 Painter — 绘制正在绘制中的笔画
//
// 接收可变点缓冲区的直接引用 + 版本号驱动重绘。
// 每帧仅计算当前笔画的轮廓路径,不影响已完成笔画层。
// isComplete: false 让 perfect_freehand 对实时笔尖做端点平滑。
import 'package:flutter/widgets.dart';
import 'stroke_model.dart';
import 'stroke_renderer.dart';
/// 当前笔画实时 Painter
///
/// 由 ListenableBuilder 包裹,监听 ValueNotifier<int> _strokeVersion。
/// 每次 pointer move 递增 version触发此 Painter 重绘。
/// 仅渲染当前正在绘制的笔画,已完成笔画由 CachedStrokesPainter 处理。
class ActiveStrokePainter extends CustomPainter {
/// 当前笔画的采样点(直接引用可变缓冲区,不拷贝)
final List<StrokePoint> 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;
}
}