用途:为 Flutter 中手绘表面(CustomPainter/Canvas)建立工程契约,确保跨平台像素一致、手势与绘制坐标一致、屏幕阅读器可读。
主要能力与规则:
- 分层:画布由 View、Painter、不可变 Scene 三部分组成,禁止单一 god-widget。View 监听 ViewModel 并构建不可变 Scene 值类型交给 CustomPaint;Painter 只负责绘制,不含 Notifier、BuildContext、DateTime 或业务规则。
- shouldRepaint 仅做 old.scene != scene 一次值比较;逐帧动画走 repaint: Listenable,两条路径不得重复重绘。
- 每次布局构建唯一仿射变换,painter 与命中测试共用,toCanvas/toLogical 互为精确逆运算,命中测试不得自行从尺寸推导缩放。
- 按几何类别命中:格点用整数除法,不规则区域用加载时栅格化一次的 Uint32List ID 缓冲,热路径禁用 Path.contains。
- paint() 内零分配:Paint/Path/Gradient 作为字段,逐元素改 .color,saveLayer 仅用于真实组混合。
- 动画由 AnimationController 作为 repaint: 驱动,不用 setState/notifyListeners;动效时长经 resolveMotion 解析,抑制时直接跳到终态;状态变化不得仅靠动效或色相传达。
- 手势处理器是纯翻译器:localPosition → 共享变换 → 命中测试 → 类型化不可变命令 → ViewModel 方法,自身不改状态;CustomPaint 外层用 HitTestBehavior.opaque。
- 一个动词一个识别器,冲突用 RawGestureDetector 显式仲裁;轴锁定拖拽用 clamp 而非逐帧碰撞。
- 规范值输入、显示值输出:不在 paint() 内换算单位、格式化日期或塑形数字;大数据在 Isolate.run 中降采样。
- 自绘表面对屏幕阅读器不透明,需显式编写 Semantics,或由 semanticsBuilder 返回逐元素节点;颜色不得是唯一信号。
- 几何与方向无关,仅装饰镜像;从 Directionality.of(context) 推导符号,使用 *Directional 内边距。
- 用 RepaintBoundary 隔离表面,如实设置 isComplex/willChange,避免全局包裹。
使用方式:按任务阅读 references/painter-and-scene.md、references/gestures-and-semantics.md、references/text-and-shapes.md;提交 PR 前运行 scripts/check_painter_hygiene.sh 与 scripts/analyze.sh。
适用场景:自绘图表、波形、格点与不规则区域交互、需无障碍支持的手绘界面。
限制:资料未提供安装命令、依赖版本、收费与平台支持信息;具体 API 以 Flutter 官方为准。