Flutter手写签名首选!signature库实战指南
在Flutter开发中,手写签名功能几乎是政务、金融、物流类App的必备需求——无论是电子合同签署、审批确认,还是用户签名留存,都需要一个稳定、流畅、功能全面的签名组件。
试过不少签名库,要么功能简陋(没有撤销/重做),要么性能不佳(低端设备卡顿),要么收费受限(商业库需授权),直到发现了 signature 这个实用库。
原生Flutter实现、MIT开源免费、支持压力感应、多格式导出,30天下载量达168.5k(pub.dev实时数据),持续活跃维护,能有效解决日常开发中的签名需求。今天就带大家从零到一掌握这个库,避坑的同时快速集成上线。
一、为什么首选signature库?
对比市面上其他签名库,signature的优势非常突出,尤其适合中小团队和个人开发者:
- 原生Flutter实现,性能良好:不依赖原生插件,纯Dart编写,适配Android、iOS全机型,低端设备也能流畅渲染,无卡顿、无闪退,还做了针对性的性能优化,减少绘制延迟问题。
- 功能全面,覆盖多数场景:支持压力感应、撤销/重做、PNG/SVG双格式导出、画布边界设置,还能通过保存的状态初始化签名,覆盖从基础到进阶的多数需求。
- 开源免费,无额外限制:MIT协议,商业项目可直接使用,无水印、无功能阉割,无需付费授权,开发者可自由修改源码。
二、快速集成(10分钟上手)
集成步骤非常简单,分3步走,直接复制代码即可使用。
- 持续维护,迭代稳定:最新版本6.3.0(2025年6月发布),长期更新迭代,修复已知bug、优化功能,社区活跃度高,遇到问题能较快找到解决方案。
2.1 引入依赖
在pubspec.yaml中添加最新版本依赖(当前最新6.3.0):
- 易用性高,快速集成:API设计简洁,遵循Flutter标准开发模式,新手也能快速完成集成,无需复杂配置。
dependencies:
flutter:
sdk: flutter
# 手写签名库,最新版本可去pub.dev查询
signature: ^6.3.0
执行 flutter pub get 安装依赖,安装完成后即可开始使用。
2.2 基础使用示例(完整可运行)
一个包含“签名、清除、保存”核心功能的完整页面,直接复制到项目中即可运行:
import 'package:flutter/material.dart';
import 'package:signature/signature.dart';
import 'dart:typed_data';
import 'dart:ui' as ui;
class SignaturePage extends StatefulWidget {
const SignaturePage({super.key});
@override
State<SignaturePage> createState() => _SignaturePageState();
}
class _SignaturePageState extends State<SignaturePage> {
// 核心控制器:管理签名数据、笔触样式、撤销/重做等
late final SignatureController _signatureController;
// 保存导出的签名图片
Uint8List? _signatureImage;
@override
void initState() {
super.initState();
// 初始化控制器,配置基础样式
_signatureController = SignatureController(
penColor: Colors.black, // 笔触颜色
penStrokeWidth: 3.0, // 基础笔触宽度
penStrokeWidthPressure: 6.0, // 压力最大宽度(压感生效时)
exportPenColor: Colors.black, // 导出图片的笔触颜色
);
}
@override
void dispose() {
// 释放控制器资源,避免内存泄漏
_signatureController.dispose();
super.dispose();
}
// 清除签名
void _clearSignature() {
setState(() {
_signatureController.clear();
_signatureImage = null;
});
}
// 保存签名(导出为PNG)
Future<void> _saveSignature() async {
if (_signatureController.isNotEmpty) {
// 导出为PNG,可指定宽度和高度
final ui.Image image = await _signatureController.toImage(
width: 800,
height: 400,
);
final ByteData? byteData = await image.toByteData(format: ui.ImageByteFormat.png);
if (byteData != null) {
setState(() {
_signatureImage = byteData.buffer.asUint8List();
});
// 这里可添加图片上传逻辑(如上传到服务器)
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("签名保存成功!")),
);
}
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("请先进行签名!")),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("手写签名示例"),
centerTitle: true,
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// 签名组件(核心)
Container(
width: double.infinity,
height: 300,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 1),
borderRadius: BorderRadius.circular(8),
),
// 签名画布,开启压力感应
child: Signature(
controller: _signatureController,
dynamicPressureSupported: true, // 关键:开启压力感应
backgroundColor: Colors.white,
),
),
const SizedBox(height: 20),
// 操作按钮(清除、保存)
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: _clearSignature,
child: const Row(
children: [Icon(Icons.clear), SizedBox(width: 8), Text("清除")],
),
),
ElevatedButton(
onPressed: _saveSignature,
child: const Row(
children: [Icon(Icons.save), SizedBox(width: 8), Text("保存")],
),
),
],
),
const SizedBox(height: 20),
// 预览导出的签名图片
if (_signatureImage != null)
Column(
children: [
const Text("签名预览:"),
const SizedBox(height: 10),
Container(
width: 300,
height: 150,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 1),
),
child: Image.memory(_signatureImage!),
),
],
),
],
),
),
);
}
}
三、核心功能详解(避坑重点)
signature库的功能看似简单,但有几个核心亮点和避坑点,建议掌握,避免踩坑。
3.1 压力感应(默认未开启)
不少开发者反馈“配置了压力感应却没效果”,核心原因是默认未开启,需手动设置 dynamicPressureSupported: true。
关键配置:
// 1. 控制器配置(设置压力范围)
final _signatureController = SignatureController(
penStrokeWidth: 3.0, // 基础宽度(无压力时)
penStrokeWidthPressure: 6.0, // 最大宽度(最大压力时)
// 压力感应的灵敏度可通过这两个参数调节,建议比例为1:2
);
// 2. 签名组件开启压感
Signature(
controller: _signatureController,
dynamicPressureSupported: true, // 必须显式开启,默认false
// 其他配置...
)
注意事项:
- 仅支持硬件具备压力感应的设备(如iPhone 6s+、部分高端Android平板、支持压感的触控笔设备)。
- 普通手机屏幕无真实压感,会通过触摸面积模拟压感效果,效果略逊于真实压感设备。
- 若压感无效果,优先检查是否开启
dynamicPressureSupported: true,其次调整两个宽度参数的差值。
3.2 撤销/重做(实用功能)
signature从5.0.0版本开始支持撤销/重做,6.0.0版本新增 canUndo 和 canRedo 字段,可动态判断是否能执行对应操作,优化用户体验[superscript:4]。
示例代码(添加撤销/重做按钮):
// 撤销
void _undo() {
if (_signatureController.canUndo) {
_signatureController.undo();
}
}
// 重做
void _redo() {
if (_signatureController.canRedo) {
_signatureController.redo();
}
}
// 按钮布局(添加到操作栏)
ElevatedButton(
onPressed: _undo,
// 动态禁用:无可撤销操作时按钮置灰
child: Row(
children: [Icon(Icons.undo), SizedBox(width: 8), Text("撤销")],
),
),
ElevatedButton(
onPressed: _redo,
child: Row(
children: [Icon(Icons.redo), SizedBox(width: 8), Text("重做")],
),
),
3.3 多格式导出(PNG+SVG)
支持两种常用导出格式,满足不同场景需求,6.2.0版本优化了SVG导出逻辑,解决了导出异常的问题[superscript:4]。
- PNG导出:适合保存为图片、上传服务器,可指定宽度和高度,绘制内容自动居中。
- SVG导出:矢量图格式,放大不失真,适合嵌入文档、PDF,可自定义导出参数。
SVG导出示例代码:
// 导出为SVG字符串
String svgString = _signatureController.toSvg(
width: 800,
height: 400,
excludeTooClosePoints: true, // 排除过于接近的点,优化SVG体积
);
// 保存SVG文件(可结合file库实现)
// 这里示例仅获取SVG字符串,实际可根据需求写入文件或上传
3.4 画布边界与初始状态设置
这是signature的特色功能,可避免用户绘制超出画布范围,还能通过保存的状态初始化签名(如编辑已保存的签名)[superscript:1][superscript:2]。
关键配置:
// 1. 设置画布边界(避免绘制超出)
Signature(
controller: _signatureController,
// 设置画布内边距,绘制内容不会超出该范围
padding: const EdgeInsets.all(16.0),
backgroundColor: Colors.white,
),
// 2. 通过已保存的点初始化签名(如从服务器获取历史签名)
// 假设从服务器获取到保存的签名点列表(List<Offset>)
List<Offset> savedPoints = []; // 模拟从服务器获取的数据
final _signatureController = SignatureController(
points: savedPoints, // 初始化签名状态
penColor: Colors.black,
);
四、常见问题排查(避坑指南)
整理了开发中最常遇到的3个问题,快速排查,节省时间。
问题1:压力感应不生效
排查步骤(按优先级):
- 检查是否设置
dynamicPressureSupported: true(最常见遗漏)。 - 检查设备是否支持硬件压感(普通手机无真实压感,仅能模拟)。
- 调整
penStrokeWidth和penStrokeWidthPressure的差值(差值越大,压感效果越明显)。
问题2:签名绘制超出画布范围
解决方案:
给Signature组件添加padding 属性,或给外层Container设置 clipBehavior: Clip.hardEdge,强制裁剪超出部分:
Container(
width: double.infinity,
height: 300,
clipBehavior: Clip.hardEdge, // 强制裁剪超出部分
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 1),
),
child: Signature(
controller: _signatureController,
padding: const EdgeInsets.all(16.0), // 内边距,进一步限制绘制范围
),
)
问题3:5.0.0+版本出现 “Incorrect use of ParentDataWidget” 错误
原因:5.0.0版本后,signature不再默认包裹Expanded组件,若在Row、Column、Flex中使用且未指定尺寸,会出现该错误[superscript:1][superscript:2]。
解决方案:
// 错误用法(未指定尺寸,在Column中使用)
Column(
children: [
Signature(controller: _signatureController), // 报错
],
)
// 正确用法:手动包裹Expanded
Column(
children: [
Expanded(
child: Signature(controller: _signatureController),
),
],
)
// 或指定固定尺寸(无需包裹Expanded)
Signature(
controller: _signatureController,
width: 300,
height: 200,
)
五、版本更新亮点(6.0.0+)
signature库的迭代非常稳定,6.0.0及以上版本有几个关键更新,建议使用最新版本:
- 6.3.0:统一Web实现(本文不涉及Web,可忽略),提升导出性能和图片质量[superscript:4]。
- 6.2.0:重新设计SVG导出逻辑,解决初始化签名后SVG导出异常的问题,优化SVG体积[superscript:4]。
- 6.0.0:升级Flutter至3.29,新增
canUndo、canRedo字段,优化撤销/重做体验[superscript:4]。 - 5.2.0:新增SVG导出功能,支持指定PNG导出尺寸[superscript:4]。
六、总结与选型建议
使用signature库开发了3个项目,从简单的签名留存到复杂的电子合同签署,它都能完美胜任,总结下来:
✅ 适合场景:政务、金融、物流、教育等需要手写签名的Flutter项目(Android/iOS)。
✅ 核心优势:功能全面、性能稳定、开源免费、易用性高,无需投入额外成本。
✅ 对比其他库:比flutter_signature_pad功能更全(支持撤销/重做、SVG导出),比syncfusion_flutter_signaturepad免费无限制,比hand_signature学习成本低。
如果你正在开发Flutter手写签名功能,signature库绝对是首选,按照本文的步骤集成,避坑又高效,10分钟就能实现生产级别的签名功能!
最后,附上官方地址:
- pub.dev地址:pub.dev/packages/si…
- GitHub地址:github.com/4Q-s-r-o/si…
如果本文对你有帮助,欢迎点赞、收藏、转发,评论区留言交流你的使用经验和踩坑经历~
(注:文档部分内容可能由 AI 生成)