syncfusion-flutter-signature-pad
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSyncfusion Flutter Signature Pad
Syncfusion Flutter 签名板
This skill covers the Syncfusion Flutter SfSignaturePad component, which provides an elegant and intuitive way to capture handwritten signatures or drawings in your Flutter applications. The component offers smooth drawing experience with touch and stylus support, along with powerful customization and export capabilities.
本技能介绍Syncfusion Flutter的SfSignaturePad组件,该组件为Flutter应用提供了优雅直观的手写签名或绘图捕获能力,支持触摸和触控笔输入,绘制体验流畅,同时具备强大的自定义和导出功能。
When to Use This Skill
何时使用本技能
Use this skill when you need to:
- Capture digital signatures for documents, forms, or agreements
- Implement e-signature functionality in approval workflows
- Create signature fields in PDF forms or digital documents
- Build document signing interfaces for contracts, receipts, or legal forms
- Add handwritten input for notes, sketches, or annotations
- Implement signature verification screens in authentication flows
- Create drawing surfaces for simple sketching or markup
- Capture user consent with signature-based authentication
- Build approval systems that require handwritten signatures
- Add signature pads to registration, checkout, or delivery confirmation screens
当你需要实现以下需求时可使用本技能:
- 捕获数字签名用于文档、表单或协议
- 在审批工作流中实现电子签名功能
- 在PDF表单或数字文档中创建签名字段
- 为合同、收据或法律表单构建文档签署界面
- 为笔记、草图或标注添加手写输入功能
- 在认证流程中实现签名验证页面
- 为简单涂鸦或标注创建绘图界面
- 通过基于签名的认证捕获用户同意
- 构建需要手写签名的审批系统
- 在注册、结账或配送确认页面添加签名板
Component Overview
组件概览
SfSignaturePad is a Flutter widget that captures smooth, high-quality signatures or drawings through touch or stylus input. It provides a customizable drawing surface with features like stroke customization, background images, minimum stroke validation, and multiple export formats.
SfSignaturePad是一款Flutter组件,可通过触摸或触控笔输入捕获流畅、高质量的签名或绘图。它提供可自定义的绘图界面,支持笔触自定义、背景图片、最小笔触校验以及多种导出格式等特性。
Key Features
核心特性
- Smooth Drawing Experience - Optimized for touch and stylus input with smooth curves
- Stroke Customization - Control stroke color, width, and appearance
- Background Support - Add background colors or images
- Minimum Stroke Validation - Ensure meaningful signatures are captured
- Multiple Export Formats - Convert to image (PNG, JPEG) or save as raw data
- Clear & Reset - Programmatically clear the signature pad
- Read-only Mode - Display signatures without allowing modifications
- Callbacks - Handle draw start, draw, and draw end events
- Transparent Background - Support for transparent signature capture
- High-Quality Output - Export signatures at desired resolution
- 流畅的绘制体验:针对触摸和触控笔输入优化,曲线绘制流畅
- 笔触自定义:可控制笔触颜色、宽度和外观
- 背景支持:可添加背景色或背景图片
- 最小笔触校验:确保捕获到有效签名
- 多种导出格式:可转换为图片(PNG、JPEG)或保存为原始数据
- 清空与重置:可通过编程方式清空签名板
- 只读模式:仅展示签名,不允许修改
- 回调机制:可处理绘制开始、绘制中、绘制结束事件
- 透明背景:支持捕获透明背景的签名
- 高质量输出:可按所需分辨率导出签名
Documentation and Navigation Guide
文档与导航指南
Getting Started
入门指南
📄 Read: references/getting-started.md
- Installation and package setup
- Basic SfSignaturePad implementation
- Package dependencies and imports
- First signature capture example
- Quick setup guide
📄 阅读: references/getting-started.md
- 安装与包配置
- SfSignaturePad基础实现
- 包依赖与导入
- 首个签名捕获示例
- 快速配置指南
Component Overview
组件概览
📄 Read: references/overview.md
- SfSignaturePad widget overview and features
- When to use SignaturePad
- Core capabilities and use cases
- Widget architecture
- Basic configuration
📄 阅读: references/overview.md
- SfSignaturePad组件概览与特性
- 何时使用签名板
- 核心能力与使用场景
- 组件架构
- 基础配置
Customization and Styling
自定义与样式
📄 Read: references/customization.md
- Stroke color customization
- Stroke width and min/max settings
- Background color and images
- Border and container styling
- Transparent backgrounds
- Visual appearance customization
- Theme integration
📄 阅读: references/customization.md
- 笔触颜色自定义
- 笔触宽度与最小/最大值设置
- 背景色与背景图片
- 边框与容器样式
- 透明背景
- 视觉外观自定义
- 主题集成
Saving and Exporting
保存与导出
📄 Read: references/saving-exporting.md
- Converting signature to image (toImage method)
- Image format options (PNG, JPEG)
- Resolution and quality settings
- Saving signatures to storage
- Converting to Uint8List
- Clearing the signature pad
- Minimum stroke count validation
- Export patterns and best practices
📄 阅读: references/saving-exporting.md
- 将签名转换为图片(toImage方法)
- 图片格式选项(PNG、JPEG)
- 分辨率与质量设置
- 将签名保存到存储
- 转换为Uint8List格式
- 清空签名板
- 最小笔触数量校验
- 导出模式与最佳实践
Event Handling
事件处理
📄 Read: references/callbacks.md
- onDrawStart callback
- onDraw callback
- onDrawEnd callback
- Handling signature events
- Validation during drawing
- Real-time feedback patterns
- Event argument types
📄 阅读: references/callbacks.md
- onDrawStart回调
- onDraw回调
- onDrawEnd回调
- 处理签名事件
- 绘制过程中校验
- 实时反馈模式
- 事件参数类型
Advanced Features
高级特性
📄 Read: references/advanced-features.md
- Read-only mode for displaying signatures
- Background image support
- Signature validation techniques
- Custom drawing constraints
- Integration with forms
- Signature comparison
- Multi-signature workflows
- Undo/redo implementation patterns
📄 阅读: references/advanced-features.md
- 用于展示签名的只读模式
- 背景图片支持
- 签名校验技术
- 自定义绘制约束
- 与表单集成
- 签名比对
- 多签名工作流
- 撤销/重做实现模式
Accessibility
无障碍支持
📄 Read: references/accessibility.md
- Screen reader support
- Semantic labels for signature fields
- Keyboard accessibility considerations
- Alternative input methods
- WCAG compliance
- Accessible signature workflows
📄 阅读: references/accessibility.md
- 屏幕阅读器支持
- 签名字段语义标签
- 键盘无障碍考量
- 替代输入方式
- WCAG合规
- 无障碍签名工作流
Quick Start Examples
快速入门示例
Basic Signature Pad
基础签名板
dart
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_signaturepad/signaturepad.dart';
class BasicSignaturePad extends StatelessWidget {
final GlobalKey<SfSignaturePadState> _signaturePadKey = GlobalKey();
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Sign Here')),
body: Column(
children: [
Padding(
padding: EdgeInsets.all(16),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
),
child: SfSignaturePad(
key: _signaturePadKey,
backgroundColor: Colors.white,
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () => _signaturePadKey.currentState!.clear(),
child: Text('Clear'),
),
ElevatedButton(
onPressed: _saveSignature,
child: Text('Save'),
),
],
),
],
),
);
}
Future<void> _saveSignature() async {
final image = await _signaturePadKey.currentState!.toImage();
// Process the image (save to file, upload, etc.)
}
}dart
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_signaturepad/signaturepad.dart';
class BasicSignaturePad extends StatelessWidget {
final GlobalKey<SfSignaturePadState> _signaturePadKey = GlobalKey();
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Sign Here')),
body: Column(
children: [
Padding(
padding: EdgeInsets.all(16),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
),
child: SfSignaturePad(
key: _signaturePadKey,
backgroundColor: Colors.white,
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () => _signaturePadKey.currentState!.clear(),
child: Text('Clear'),
),
ElevatedButton(
onPressed: _saveSignature,
child: Text('Save'),
),
],
),
],
),
);
}
Future<void> _saveSignature() async {
final image = await _signaturePadKey.currentState!.toImage();
// Process the image (save to file, upload, etc.)
}
}Customized Signature Pad
自定义签名板
dart
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_signaturepad/signaturepad.dart';
class CustomSignaturePad extends StatelessWidget {
final GlobalKey<SfSignaturePadState> _signaturePadKey = GlobalKey();
Widget build(BuildContext context) {
return SfSignaturePad(
key: _signaturePadKey,
backgroundColor: Colors.grey[100],
strokeColor: Colors.blue,
minimumStrokeWidth: 1.0,
maximumStrokeWidth: 4.0,
onDrawStart: () {
print('Started drawing');
return true;
},
onDraw: (offset, time) {
print('Drawing at: $offset');
},
onDrawEnd: () {
print('Finished drawing');
},
);
}
}dart
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_signaturepad/signaturepad.dart';
class CustomSignaturePad extends StatelessWidget {
final GlobalKey<SfSignaturePadState> _signaturePadKey = GlobalKey();
Widget build(BuildContext context) {
return SfSignaturePad(
key: _signaturePadKey,
backgroundColor: Colors.grey[100],
strokeColor: Colors.blue,
minimumStrokeWidth: 1.0,
maximumStrokeWidth: 4.0,
onDrawStart: () {
print('Started drawing');
return true;
},
onDraw: (offset, time) {
print('Drawing at: $offset');
},
onDrawEnd: () {
print('Finished drawing');
},
);
}
}Signature Pad with Validation
带校验的签名板
dart
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_signaturepad/signaturepad.dart';
import 'dart:ui' as ui;
class ValidatedSignaturePad extends StatefulWidget {
_ValidatedSignaturePadState createState() => _ValidatedSignaturePadState();
}
class _ValidatedSignaturePadState extends State<ValidatedSignaturePad> {
final GlobalKey<SfSignaturePadState> _signaturePadKey = GlobalKey();
String _validationMessage = '';
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Sign Document')),
body: Column(
children: [
Expanded(
child: Padding(
padding: EdgeInsets.all(16),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 2),
borderRadius: BorderRadius.circular(8),
),
child: SfSignaturePad(
key: _signaturePadKey,
backgroundColor: Colors.white,
strokeColor: Colors.black,
minimumStrokeWidth: 2.0,
maximumStrokeWidth: 4.0,
),
),
),
),
if (_validationMessage.isNotEmpty)
Padding(
padding: EdgeInsets.all(8),
child: Text(
_validationMessage,
style: TextStyle(color: Colors.red),
),
),
Padding(
padding: EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
OutlinedButton(
onPressed: _clearSignature,
child: Text('Clear'),
),
ElevatedButton(
onPressed: _saveSignature,
child: Text('Save Signature'),
),
],
),
),
],
),
);
}
void _clearSignature() {
setState(() {
_signaturePadKey.currentState!.clear();
_validationMessage = '';
});
}
Future<void> _saveSignature() async {
// Validate minimum stroke count
if (_signaturePadKey.currentState!.toImage == null) {
setState(() {
_validationMessage = 'Please provide a signature';
});
return;
}
try {
final ui.Image image = await _signaturePadKey.currentState!.toImage(
pixelRatio: 3.0,
);
// Convert to bytes
final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
final bytes = byteData!.buffer.asUint8List();
// Save or upload the signature
print('Signature saved: ${bytes.length} bytes');
setState(() {
_validationMessage = 'Signature saved successfully!';
});
// Navigate or perform next action
} catch (e) {
setState(() {
_validationMessage = 'Error saving signature: $e';
});
}
}
}dart
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_signaturepad/signaturepad.dart';
import 'dart:ui' as ui;
class ValidatedSignaturePad extends StatefulWidget {
_ValidatedSignaturePadState createState() => _ValidatedSignaturePadState();
}
class _ValidatedSignaturePadState extends State<ValidatedSignaturePad> {
final GlobalKey<SfSignaturePadState> _signaturePadKey = GlobalKey();
String _validationMessage = '';
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Sign Document')),
body: Column(
children: [
Expanded(
child: Padding(
padding: EdgeInsets.all(16),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey, width: 2),
borderRadius: BorderRadius.circular(8),
),
child: SfSignaturePad(
key: _signaturePadKey,
backgroundColor: Colors.white,
strokeColor: Colors.black,
minimumStrokeWidth: 2.0,
maximumStrokeWidth: 4.0,
),
),
),
),
if (_validationMessage.isNotEmpty)
Padding(
padding: EdgeInsets.all(8),
child: Text(
_validationMessage,
style: TextStyle(color: Colors.red),
),
),
Padding(
padding: EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
OutlinedButton(
onPressed: _clearSignature,
child: Text('Clear'),
),
ElevatedButton(
onPressed: _saveSignature,
child: Text('Save Signature'),
),
],
),
),
],
),
);
}
void _clearSignature() {
setState(() {
_signaturePadKey.currentState!.clear();
_validationMessage = '';
});
}
Future<void> _saveSignature() async {
// Validate minimum stroke count
if (_signaturePadKey.currentState!.toImage == null) {
setState(() {
_validationMessage = 'Please provide a signature';
});
return;
}
try {
final ui.Image image = await _signaturePadKey.currentState!.toImage(
pixelRatio: 3.0,
);
// Convert to bytes
final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
final bytes = byteData!.buffer.asUint8List();
// Save or upload the signature
print('Signature saved: ${bytes.length} bytes');
setState(() {
_validationMessage = 'Signature saved successfully!';
});
// Navigate or perform next action
} catch (e) {
setState(() {
_validationMessage = 'Error saving signature: $e';
});
}
}
}Signature Pad with Background Image
带背景图片的签名板
dart
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_signaturepad/signaturepad.dart';
class SignatureWithBackground extends StatelessWidget {
final GlobalKey<SfSignaturePadState> _signaturePadKey = GlobalKey();
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
image: DecorationImage(
image: AssetImage('assets/signature_background.png'),
fit: BoxFit.cover,
opacity: 0.3,
),
),
child: SfSignaturePad(
key: _signaturePadKey,
backgroundColor: Colors.transparent,
strokeColor: Colors.blue[900]!,
minimumStrokeWidth: 2.0,
maximumStrokeWidth: 5.0,
),
);
}
}dart
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_signaturepad/signaturepad.dart';
class SignatureWithBackground extends StatelessWidget {
final GlobalKey<SfSignaturePadState> _signaturePadKey = GlobalKey();
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
image: DecorationImage(
image: AssetImage('assets/signature_background.png'),
fit: BoxFit.cover,
opacity: 0.3,
),
),
child: SfSignaturePad(
key: _signaturePadKey,
backgroundColor: Colors.transparent,
strokeColor: Colors.blue[900]!,
minimumStrokeWidth: 2.0,
maximumStrokeWidth: 5.0,
),
);
}
}Common Patterns
常用模式
Pattern 1: Document Signing Flow
模式1:文档签署流程
dart
class DocumentSigningFlow extends StatefulWidget {
_DocumentSigningFlowState createState() => _DocumentSigningFlowState();
}
class _DocumentSigningFlowState extends State<DocumentSigningFlow> {
final GlobalKey<SfSignaturePadState> _signaturePadKey = GlobalKey();
bool _hasSignature = false;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Sign Agreement')),
body: Column(
children: [
// Document preview
Expanded(
flex: 2,
child: Container(
padding: EdgeInsets.all(16),
child: Text('Agreement Terms...'),
),
),
// Signature section
Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Your Signature',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Container(
height: 200,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: SfSignaturePad(
key: _signaturePadKey,
backgroundColor: Colors.white,
strokeColor: Colors.black,
minimumStrokeWidth: 2.0,
maximumStrokeWidth: 4.0,
onDrawEnd: () {
setState(() => _hasSignature = true);
},
),
),
],
),
),
// Action buttons
Padding(
padding: EdgeInsets.all(16),
child: Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: _clearSignature,
child: Text('Clear'),
),
),
SizedBox(width: 16),
Expanded(
child: ElevatedButton(
onPressed: _hasSignature ? _submitSignature : null,
child: Text('Submit'),
),
),
],
),
),
],
),
);
}
void _clearSignature() {
setState(() {
_signaturePadKey.currentState!.clear();
_hasSignature = false;
});
}
Future<void> _submitSignature() async {
final image = await _signaturePadKey.currentState!.toImage(pixelRatio: 3.0);
// Submit signature with document
Navigator.pop(context, image);
}
}dart
class DocumentSigningFlow extends StatefulWidget {
_DocumentSigningFlowState createState() => _DocumentSigningFlowState();
}
class _DocumentSigningFlowState extends State<DocumentSigningFlow> {
final GlobalKey<SfSignaturePadState> _signaturePadKey = GlobalKey();
bool _hasSignature = false;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Sign Agreement')),
body: Column(
children: [
// Document preview
Expanded(
flex: 2,
child: Container(
padding: EdgeInsets.all(16),
child: Text('Agreement Terms...'),
),
),
// Signature section
Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Your Signature',
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Container(
height: 200,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: SfSignaturePad(
key: _signaturePadKey,
backgroundColor: Colors.white,
strokeColor: Colors.black,
minimumStrokeWidth: 2.0,
maximumStrokeWidth: 4.0,
onDrawEnd: () {
setState(() => _hasSignature = true);
},
),
),
],
),
),
// Action buttons
Padding(
padding: EdgeInsets.all(16),
child: Row(
children: [
Expanded(
child: OutlinedButton(
onPressed: _clearSignature,
child: Text('Clear'),
),
),
SizedBox(width: 16),
Expanded(
child: ElevatedButton(
onPressed: _hasSignature ? _submitSignature : null,
child: Text('Submit'),
),
),
],
),
),
],
),
);
}
void _clearSignature() {
setState(() {
_signaturePadKey.currentState!.clear();
_hasSignature = false;
});
}
Future<void> _submitSignature() async {
final image = await _signaturePadKey.currentState!.toImage(pixelRatio: 3.0);
// Submit signature with document
Navigator.pop(context, image);
}
}Pattern 2: Multiple Signatures Collection
模式2:多签名收集
dart
class MultipleSignaturesForm extends StatefulWidget {
_MultipleSignaturesFormState createState() => _MultipleSignaturesFormState();
}
class _MultipleSignaturesFormState extends State<MultipleSignaturesForm> {
final GlobalKey<SfSignaturePadState> _applicantKey = GlobalKey();
final GlobalKey<SfSignaturePadState> _witnessKey = GlobalKey();
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Signatures Required')),
body: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSignatureField(
'Applicant Signature',
_applicantKey,
),
SizedBox(height: 24),
_buildSignatureField(
'Witness Signature',
_witnessKey,
),
SizedBox(height: 24),
ElevatedButton(
onPressed: _submitAllSignatures,
child: Text('Submit All'),
),
],
),
),
);
}
Widget _buildSignatureField(String label, GlobalKey<SfSignaturePadState> key) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
SizedBox(height: 8),
Container(
height: 150,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: SfSignaturePad(
key: key,
backgroundColor: Colors.white,
strokeColor: Colors.blue[900]!,
),
),
TextButton(
onPressed: () => key.currentState!.clear(),
child: Text('Clear'),
),
],
);
}
Future<void> _submitAllSignatures() async {
final applicantImage = await _applicantKey.currentState!.toImage();
final witnessImage = await _witnessKey.currentState!.toImage();
// Submit both signatures
}
}dart
class MultipleSignaturesForm extends StatefulWidget {
_MultipleSignaturesFormState createState() => _MultipleSignaturesFormState();
}
class _MultipleSignaturesFormState extends State<MultipleSignaturesForm> {
final GlobalKey<SfSignaturePadState> _applicantKey = GlobalKey();
final GlobalKey<SfSignaturePadState> _witnessKey = GlobalKey();
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Signatures Required')),
body: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSignatureField(
'Applicant Signature',
_applicantKey,
),
SizedBox(height: 24),
_buildSignatureField(
'Witness Signature',
_witnessKey,
),
SizedBox(height: 24),
ElevatedButton(
onPressed: _submitAllSignatures,
child: Text('Submit All'),
),
],
),
),
);
}
Widget _buildSignatureField(String label, GlobalKey<SfSignaturePadState> key) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
SizedBox(height: 8),
Container(
height: 150,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: SfSignaturePad(
key: key,
backgroundColor: Colors.white,
strokeColor: Colors.blue[900]!,
),
),
TextButton(
onPressed: () => key.currentState!.clear(),
child: Text('Clear'),
),
],
);
}
Future<void> _submitAllSignatures() async {
final applicantImage = await _applicantKey.currentState!.toImage();
final witnessImage = await _witnessKey.currentState!.toImage();
// Submit both signatures
}
}Pattern 3: Read-only Signature Display
模式3:只读签名展示
dart
class SignatureDisplay extends StatefulWidget {
final Uint8List signatureData;
SignatureDisplay({required this.signatureData});
_SignatureDisplayState createState() => _SignatureDisplayState();
}
class _SignatureDisplayState extends State<SignatureDisplay> {
Widget build(BuildContext context) {
return Container(
height: 200,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: Image.memory(
widget.signatureData,
fit: BoxFit.contain,
),
);
}
}dart
class SignatureDisplay extends StatefulWidget {
final Uint8List signatureData;
SignatureDisplay({required this.signatureData});
_SignatureDisplayState createState() => _SignatureDisplayState();
}
class _SignatureDisplayState extends State<SignatureDisplay> {
Widget build(BuildContext context) {
return Container(
height: 200,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
child: Image.memory(
widget.signatureData,
fit: BoxFit.contain,
),
);
}
}Pattern 4: Signature with Real-time Feedback
模式4:带实时反馈的签名
dart
class InteractiveSignaturePad extends StatefulWidget {
_InteractiveSignaturePadState createState() => _InteractiveSignaturePadState();
}
class _InteractiveSignaturePadState extends State<InteractiveSignaturePad> {
final GlobalKey<SfSignaturePadState> _signaturePadKey = GlobalKey();
bool _isDrawing = false;
int _strokeCount = 0;
Widget build(BuildContext context) {
return Column(
children: [
Container(
height: 300,
decoration: BoxDecoration(
border: Border.all(
color: _isDrawing ? Colors.blue : Colors.grey,
width: _isDrawing ? 2 : 1,
),
borderRadius: BorderRadius.circular(8),
),
child: SfSignaturePad(
key: _signaturePadKey,
backgroundColor: Colors.white,
strokeColor: Colors.black,
minimumStrokeWidth: 2.0,
maximumStrokeWidth: 4.0,
onDrawStart: () {
setState(() {
_isDrawing = true;
_strokeCount++;
});
return true;
},
onDrawEnd: () {
setState(() {
_isDrawing = false;
});
},
),
),
SizedBox(height: 8),
Text(
_isDrawing ? 'Drawing...' : 'Stroke count: $_strokeCount',
style: TextStyle(color: Colors.grey[600]),
),
],
);
}
}dart
class InteractiveSignaturePad extends StatefulWidget {
_InteractiveSignaturePadState createState() => _InteractiveSignaturePadState();
}
class _InteractiveSignaturePadState extends State<InteractiveSignaturePad> {
final GlobalKey<SfSignaturePadState> _signaturePadKey = GlobalKey();
bool _isDrawing = false;
int _strokeCount = 0;
Widget build(BuildContext context) {
return Column(
children: [
Container(
height: 300,
decoration: BoxDecoration(
border: Border.all(
color: _isDrawing ? Colors.blue : Colors.grey,
width: _isDrawing ? 2 : 1,
),
borderRadius: BorderRadius.circular(8),
),
child: SfSignaturePad(
key: _signaturePadKey,
backgroundColor: Colors.white,
strokeColor: Colors.black,
minimumStrokeWidth: 2.0,
maximumStrokeWidth: 4.0,
onDrawStart: () {
setState(() {
_isDrawing = true;
_strokeCount++;
});
return true;
},
onDrawEnd: () {
setState(() {
_isDrawing = false;
});
},
),
),
SizedBox(height: 8),
Text(
_isDrawing ? 'Drawing...' : 'Stroke count: $_strokeCount',
style: TextStyle(color: Colors.grey[600]),
),
],
);
}
}Key Properties
核心属性
Essential Properties
基础属性
- - Background color of the signature pad (Color)
backgroundColor - - Color of the signature strokes (Color, default: Colors.black)
strokeColor - - Minimum width of strokes (double, default: 1.0)
minimumStrokeWidth - - Maximum width of strokes (double, default: 4.0)
maximumStrokeWidth
- :签名板的背景色(Color类型)
backgroundColor - :签名笔触的颜色(Color类型,默认:Colors.black)
strokeColor - :笔触最小宽度(double类型,默认:1.0)
minimumStrokeWidth - :笔触最大宽度(double类型,默认:4.0)
maximumStrokeWidth
Callback Properties
回调属性
- - Callback when drawing starts (SignatureOnDrawStartCallback → bool Function(); return true to allow drawing, false to cancel)
onDrawStart - - Callback during drawing with offset and timestamp (DrawCallback)
onDraw - - Callback when drawing ends (VoidCallback)
onDrawEnd
- :绘制开始时触发的回调(SignatureOnDrawStartCallback → bool Function(); 返回true允许绘制,返回false取消绘制)
onDrawStart - :绘制过程中触发的回调,携带坐标偏移和时间戳(DrawCallback类型)
onDraw - :绘制结束时触发的回调(VoidCallback类型)
onDrawEnd
State Methods (via GlobalKey)
状态方法(通过GlobalKey调用)
- - Clears all strokes from the signature pad
clear() - - Converts signature to ui.Image
toImage({double pixelRatio})- - Resolution multiplier (default: 1.0, higher = better quality)
pixelRatio
- :清空签名板上的所有笔触
clear() - :将签名转换为ui.Image对象
toImage({double pixelRatio})- :分辨率倍数(默认:1.0,数值越大质量越高)
pixelRatio
Common Use Cases
常见使用场景
- Contract Signing - Digital signature capture for legal documents and agreements
- Delivery Confirmation - Capture recipient signatures for package deliveries
- Medical Consent Forms - Patient signatures for consent and authorization
- Registration Forms - User signatures during account creation or registration
- Checkout Process - Signature capture during payment or purchase completion
- Approval Workflows - Manager or authority signatures for approvals
- Receipt Acknowledgment - Customer signatures on digital receipts
- Time Sheet Signing - Employee signatures for attendance or timesheet approval
- Visitor Management - Visitor signatures during check-in processes
- Terms Acceptance - Signature-based acceptance of terms and conditions
- 合同签署:为法律文档和协议捕获数字签名
- 配送确认:捕获收件人签名用于包裹交付确认
- 医疗同意书:捕获患者签名用于同意和授权
- 注册表单:用户创建账号或注册过程中的签名收集
- 结账流程:支付或购买完成过程中的签名捕获
- 审批工作流:管理人员或权限方的审批签名
- 收据确认:客户在电子收据上的签名
- 工时表签署:员工考勤或工时审批的签名
- 访客管理:访客签到流程中的签名收集
- 条款接受:基于签名的条款与条件接受确认
Best Practices
最佳实践
Validation
校验
dart
// Always validate before saving
Future<bool> validateSignature() async {
try {
final image = await _signaturePadKey.currentState!.toImage();
// Check if image has meaningful content
return true;
} catch (e) {
return false; // No signature drawn
}
}dart
// 保存前始终进行校验
Future<bool> validateSignature() async {
try {
final image = await _signaturePadKey.currentState!.toImage();
// 检查图片是否包含有效内容
return true;
} catch (e) {
return false; // 未绘制签名
}
}Image Quality
图片质量
dart
// Use higher pixel ratio for better quality
final image = await _signaturePadKey.currentState!.toImage(
pixelRatio: 3.0, // 3x resolution for high-quality signatures
);dart
// 使用更高的像素比获得更好的质量
final image = await _signaturePadKey.currentState!.toImage(
pixelRatio: 3.0, // 3倍分辨率,用于生成高质量签名
);User Experience
用户体验
- Provide clear "Clear" and "Save" buttons
- Show visual feedback during drawing (border highlight)
- Display validation messages clearly
- Consider adding "Sign Here" indicator or background watermark
- Allow users to retry if they make mistakes
- Show confirmation after successful signature capture
- 提供清晰的「清空」和「保存」按钮
- 绘制过程中展示视觉反馈(边框高亮)
- 清晰展示校验提示信息
- 考虑添加「在此签名」提示或背景水印
- 允许用户在出错时重试
- 签名捕获成功后展示确认提示
Storage
存储
dart
import 'dart:ui' as ui;
import 'dart:typed_data';
Future<Uint8List> getSignatureBytes() async {
final ui.Image image = await _signaturePadKey.currentState!.toImage(
pixelRatio: 3.0,
);
final ByteData? byteData = await image.toByteData(
format: ui.ImageByteFormat.png,
);
return byteData!.buffer.asUint8List();
}dart
import 'dart:ui' as ui;
import 'dart:typed_data';
Future<Uint8List> getSignatureBytes() async {
final ui.Image image = await _signaturePadKey.currentState!.toImage(
pixelRatio: 3.0,
);
final ByteData? byteData = await image.toByteData(
format: ui.ImageByteFormat.png,
);
return byteData!.buffer.asUint8List();
}Tips and Gotchas
提示与注意事项
- Always use a to access signature pad methods
GlobalKey<SfSignaturePadState> - Call before navigating away to preserve the signature
toImage() - Higher values produce larger files but better quality
pixelRatio - Clear the pad when validation fails to avoid confusion
- Test on both touch devices and stylus-enabled devices
- Consider adding a stroke count check for validation
- Use contrasting colors for stroke and background for visibility
- Provide adequate height (150-300px) for comfortable signing
- 始终使用来访问签名板的方法
GlobalKey<SfSignaturePadState> - 跳转页面前调用保存签名,避免丢失
toImage() - 更高的会生成更大的文件,但质量更好
pixelRatio - 校验失败时清空签名板,避免用户混淆
- 在触摸设备和支持触控笔的设备上都进行测试
- 校验时可考虑添加笔触数量检查
- 笔触和背景使用对比色,提升可见性
- 提供足够的高度(150-300px),保证签名体验舒适