文章目录
1 手写签名效果图
2 实现手写签名
2.1 使用GestureDetector监听手势并记录
Flutter提供的GestureDetector可以监听手势变化,我们可以将签名时的手势滑动路径记录下来,然后再绘制。
- 手从开始移动到离开屏幕为 写了一笔画,由Path来记录笔画的路径。
- List<Path> 来记录所有的笔画,凑成完整的签名。
class HandwrittenSignatureWidget extends StatefulWidget {
const HandwrittenSignatureWidget({
Key? key}) : super(key: key);
@override
State<StatefulWidget> createState() => _HandwrittenSignatureWidgetState();
}
class _HandwrittenSignatureWidgetState
extends State<HandwrittenSignatureWidget> {
// 记录一次 不间断的手势路径 即记录一次 笔画
Path? _path;
// 在一次不间断的移动过程中 记录上一坐标点 用于在前后2点之间绘制贝塞尔曲线
Offset? _previousOffset;
// 记录所有的笔画 可拼凑成完整字
final List<Path?> _pathList = [];
@override
Widget build(BuildContext context) {
return GestureDetector(
//手解除到屏幕,在开始移动了
onPanStart: (details) {
// 获取当前的坐标
var position = details.localPosition;
// 每次重新开始时就是新的Path对象
_path = Path()..moveTo(position.dx, position.dy);
_previousOffset = position;
},
//持续移动中
onPanUpdate: (details) {
// 获取当前的坐标
var position = details.localPosition;
var dx = position.dx;
var dy = position.dy;
final previousOffset = _previousOffset;
//如果没有上一坐标点
if (previousOffset == null) {
_path?.lineTo(dx, dy);
} else {
var previousDx = previousOffset.dx;
var previousDy = previousOffset.dy;
// 已贝塞尔曲线的方式连线
_path?.quadraticBezierTo(
previousDx,
previousDy,
(previousDx + dx) / 2,
(previousDy + dy) / 2,
);
}
_previousOffset = position;
},
// 手停止了移动 离开了屏幕
onPanEnd: (details) {
// 记录笔画,然后清空临时变量
_pathList.add(_path);
_previousOffset = null;
_path = null;
},
);
}
}
2.2 使用CustomPainter绘制手写签名
绘制手写签名需要用到 CustomPaint 与 CustomPainter
- CustomPaint 是一个Widget ,提供了绘制时所需的画布。
- CustomPainter 一个用于实现CustomPaint绘制的接口,需要实现此接口来进行自定义绘制。
首先自定义CustomPainter
class SignaturePainter extends CustomPainter {
// 绘制签名需要 历史的笔画
final List<Path?> pathList;
// 当前正在写 的笔画
final Path? currentPath;
SignaturePainter(this.pathList, this.currentPath);
// 设置画笔的属性
final _paint = Paint()
..color = Colors.black
..style = PaintingStyle.stroke
..strokeCap = StrokeCap.round // 线条两端的形状
..strokeJoin = StrokeJoin.round // 2条线段连接处的形状
..strokeWidth = 2 //线宽
..isAntiAlias = true; //抗锯齿
@override
void paint(Canvas canvas, Size size) {
// 绘制以前写过的笔画
for (Path? path in pathList) {
_drawLine(canvas, path);
}
// 绘制当前正在写的笔画
_drawLine(canvas, currentPath);
}
void _drawLine(Canvas canvas, Path? path) {
if (path ==