深入 scratcher 源码:BlendMode.clear 擦除效果与 ScratchPainter 实现原理剖析

发布时间:2026/8/20 19:31:19
深入 scratcher 源码:BlendMode.clear 擦除效果与 ScratchPainter 实现原理剖析 深入 scratcher 源码BlendMode.clear 擦除效果与 ScratchPainter 实现原理剖析【免费下载链接】scratcherScratch card widget which temporarily hides content from user.项目地址: https://gitcode.com/gh_mirrors/sc/scratcherscratcher 是一款开箱即用的 Flutter 刮刮卡组件它用一层涂层临时隐藏用户内容手指划过时涂层被擦除露出底下的奖品或图片。很多开发者好奇刮刮卡的擦除效果到底是怎么做到的答案藏在 BlendMode.clear 与 ScratchPainter 这两个关键词里。本文将从源码层面逐行剖析 ScratchPainter 的实现原理讲清楚 BlendMode.clear 擦除效果的完整链路帮助你彻底理解 Flutter 自定义绘制与混合模式的配合方式。scratcher 是什么一个开箱即用的 Flutter 刮刮卡组件在正式看代码之前先明确 scratcher 的能力边界。它的核心职责只有一个用一层可擦除的涂层覆盖任意 child 组件。开发者只需要把内容包进Scratcher里剩下的交互、绘制、进度回调都由组件自己完成Scratcher( brushSize: 30, threshold: 50, color: Colors.red, onChange: (value) print(Scratch progress: $value%), child: Container(color: Colors.blue), )这短短几行代码背后隐藏着一套涂层绘制 手势采集 路径擦除 进度计算的完整机制而其中最核心的技术难点就是如何让涂层被擦掉而不是覆盖——这正是BlendMode.clear的用武之地。核心源码文件导读从 widgets 到 painterscratcher 的源码结构非常精简只有 4 个文件理解起来毫无负担文件职责widgets.dartScratcher组件本体负责手势、进度与状态管理painter.dartScratchPainter自定义画笔负责所有绘制逻辑utils.dartScratchPoint数据模型记录笔迹点scratcher.dart库入口对外导出 API绘制层面的全部秘密都集中在 painter.dart 这个文件里。它是整个刮刮卡效果的心脏。揭开 BlendMode.clear 擦除效果的秘密Flutter 的Paint默认使用BlendMode.srcOver新绘制的内容会直接覆盖在旧内容之上。如果直接用这种方式画涂层手指划过只会叠加出新的颜色永远无法露出下面的内容。saveLayer 为什么是擦除的前提scratch 效果的关键在于BlendMode.clear会把像素变成透明。但透明效果只对当前图层有效如果涂层和隐藏内容画在同一层clear 会把底层内容一并清掉。因此 painter.dart 里先用canvas.saveLayer(null, Paint())开启一个独立的离屏图层canvas.saveLayer(null, Paint()); // ... 绘制涂层与笔迹 canvas.restore();涂层和擦除笔迹都在这个隔离图层内完成BlendMode.clear只影响涂层像素被擦透的地方会自动露出图层下方真正的 child 内容这正是刮刮卡效果能成立的根基。drawRect drawPath 的绘制组合图层准备好之后绘制流程分三步走铺满涂层canvas.drawRect用指定颜色或图片把整个区域盖住见 painter.dart收集笔迹手势期间采集到的一串ScratchPoint被连成一条Path见 painter.dart擦除笔迹用BlendMode.clear画笔描边这条路径涂层上被描过的地方全部变透明见 painter.dart。ScratchPainter 实现原理逐行拆解 paint 方法ScratchPainter继承自CustomPainter它的paint方法就是整个绘制过程的总指挥。其中最关键的是擦除画笔的构造在_getMainPaint中完成painter.dartfinal paint Paint() ..strokeCap StrokeCap.round ..color Colors.white ..strokeWidth strokeWidth ..blendMode BlendMode.clear ..strokeJoin StrokeJoin.round ..style PaintingStyle.stroke;这里有几个细节值得注意style PaintingStyle.stroke只描边不填充擦除区域就是手指划过的笔迹带strokeCap StrokeCap.round笔迹两端是圆头保证每段笔迹衔接自然不会出现直角毛刺strokeWidth来自笔迹点每个ScratchPoint都携带自己的尺寸对应brushSize参数所以擦除笔画的粗细可以动态变化color无关紧要在BlendMode.clear下画笔颜色不会参与合成写Colors.white只是占位。涂层与图片的绘制顺序涂层不一定是纯色scratcher 也支持用本地图片当涂层。源码中的顺序是先画纯色打底painter.dart如果有image参数再用drawImageRect按BoxFit适配绘制图片painter.dart。两者都在擦除之前完成所以无论是色块还是图片涂层都能被统一擦穿。笔迹路径的采集与绘制路径的构建逻辑值得一提手势产生的ScratchPoint依次lineTo连成一条折线每当遇到一个position null的断点代表一次手势结束就把已连好的路径立即绘制并重置见 painter.dart。这样每一次按下-滑动-抬起都对应一段独立的擦除路径互不干扰。刮除进度计算原理与 ScratchAccuracy 精度擦除效果之外进度计算同样是刮刮卡体验的重要一环。scratcher 的做法相当巧妙用均匀分布的采样点代替像素级检测。在 widgets.dart 的_calculateCheckpoints中组件按精度把刮卡区域划分成网格生成一张检测点阵每次擦除笔迹经过某个点时用_inCircle判断该点是否落在笔刷半径内命中就从待刮集合中移除widgets.dartfinal accuracy _getAccuracyValue(widget.accuracy); // 把区域按 accuracy 均分为网格网格交点即检测点ScratchAccuracy枚举控制网格密度widgets.dartlow对应 10×10 网格、high对应 100×100 网格。网格越密进度越精确但每次擦除需要遍历的检测点也越多。理解这个设计后你就能明白为什么官方建议在性能敏感的场景比如小尺寸刮卡使用ScratchAccuracy.low。源码之外如何在项目中使用 scratcher虽然本文聚焦源码但了解实现原理后使用姿势也更清晰了换涂层默认color是纯色传image参数即可换成图片涂层就像 example/lib/basic.dart 演示的那样控制刮卡通过GlobalKeyScratcherState调用reset/reveal方法可编程地重置或直接揭开全部涂层widgets.dart监听事件onScratchStart/onScratchUpdate/onScratchEnd覆盖刮卡全生命周期onThreshold在刮开比例达标时触发。总结回顾整个 scratch 效果的实现链路核心只有三步saveLayer建立隔离图层 →drawRect铺满涂层 →drawPath配合BlendMode.clear擦出笔迹。ScratchPainter 实现原理的本质就是一次标准的离屏绘制 混合模式组合应用。理解BlendMode.clear之后你不仅能看懂 scratcher还能举一反三橡皮擦工具、遮罩揭露动画、图片局部擦除……这类擦除类交互在 Flutter 里都可以用同一套思路实现。希望这篇文章能帮你真正吃透这个短小精悍的开源组件从此看到 CustomPainter 不再发怵。【免费下载链接】scratcherScratch card widget which temporarily hides content from user.项目地址: https://gitcode.com/gh_mirrors/sc/scratcher创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考