鸿蒙+flutter 跨平台开发——支持自定义的打印纸生成器实战
本文介绍了使用Flutter开发鸿蒙系统下的自定义打印纸生成器应用。该应用支持多种打印纸类型(A4纸、收据纸、标签纸),提供纸张颜色自定义、网格线显示、文本编辑和打印模拟等功能。技术实现上采用Flutter框架,通过CustomPaint实现撕边效果,使用AnimationController处理打印动画。文章详细阐述了项目架构、核心流程(包括打印纸生成和打印模拟流程),并展示了关键代码片段(如打
鸿蒙+flutter 跨平台开发——支持自定义的打印纸生成器实战
🚀运行效果展示


🎯 前言
在移动应用开发领域,跨平台技术已经成为趋势。Flutter作为Google推出的UI框架,以其"Write Once, Run Anywhere"的理念,深受开发者喜爱。而鸿蒙系统作为华为自主研发的分布式操作系统,也在快速发展。本文将介绍如何使用Flutter框架开发一款支持鸿蒙系统的自定义打印纸生成器,包括多种纸张类型、自定义颜色、网格线、文本编辑和打印模拟等功能。
打印纸生成器作为一种实用工具,可以帮助用户快速创建各种类型的打印纸,如A4纸、收据纸和标签纸等,具有广泛的应用场景。
📱 项目介绍
功能特点
- ✅ 多种打印纸类型:支持A4纸、收据纸和标签纸
- 🎨 自定义纸张颜色:可选择白色、浅灰、米黄和浅蓝等颜色
- 📏 网格线显示:支持开关网格线,方便对齐和排版
- ✏️ 文本编辑功能:支持多行文本输入,实时更新打印预览
- 🖨️ 打印模拟效果:具有打印动画和进度显示
- 💾 保存和分享:支持保存当前配置和分享打印内容
技术栈
- Flutter:UI框架
- Dart:开发语言
- 鸿蒙系统:运行平台
- 状态管理:使用StatefulWidget和AnimationController
- 自定义绘制:使用CustomPaint实现撕边效果
🔧 核心功能实现
多种打印纸类型
打印纸生成器支持三种不同类型的打印纸:
| 纸张类型 | 宽度(mm) | 高度(mm) | 边距(mm) |
|---|---|---|---|
| A4纸 | 210 | 297 | 20 |
| 收据纸 | 80 | 300 | 10 |
| 标签纸 | 100 | 150 | 5 |
每种纸张类型都有其特定的尺寸和边距,用户可以通过下拉菜单进行选择。
自定义颜色选择
用户可以选择四种不同的纸张颜色:
- 白色
- 浅灰
- 米黄
- 浅蓝
颜色选择通过弹出对话框实现,用户点击颜色选项即可切换纸张颜色。
文本编辑功能
打印纸生成器支持多行文本输入,用户可以在文本框中输入要打印的内容,实时更新打印预览。文本框支持以下功能:
- 多行输入
- 支持项目符号
- 自动换行
- 实时预览更新
打印模拟效果
打印模拟功能包括:
- 打印动画:使用AnimationController实现平滑的打印进度动画
- 进度显示:LinearProgressIndicator显示打印进度
- 完成提示:打印完成后显示SnackBar提示
撕边效果实现
撕边效果使用CustomPaint自定义绘制实现,通过Path绘制波浪形撕边效果,增强打印纸的真实感。
📊 项目架构
📦 lib
├── 📁 screens
│ ├── 📄 print_paper_simulator_screen.dart # 打印纸模拟器主页面
│ └── 📄 multi_function_flip_clock_screen.dart # 多功能翻页时钟页面
└── 📄 main.dart # 应用入口
🌟 核心流程
打印纸生成流程
打印模拟流程
💻 代码展示
打印纸类型定义
/// 打印纸类型枚举
enum PaperType {
/// A4纸
a4,
/// 收据纸
receipt,
/// 标签纸
label,
}
打印纸预览构建
/// 构建打印纸预览
Widget _buildPaperPreview() {
// 初始化默认值
double paperWidth = 210.0;
double paperHeight = 297.0;
double margin = 20.0;
// 根据不同纸张类型设置尺寸
switch (_currentPaperType) {
case PaperType.a4:
paperWidth = 210.0; // A4宽度,单位:mm
paperHeight = 297.0;
margin = 20.0;
break;
case PaperType.receipt:
paperWidth = 80.0; // 收据宽度,单位:mm
paperHeight = 300.0;
margin = 10.0;
break;
case PaperType.label:
paperWidth = 100.0; // 标签宽度,单位:mm
paperHeight = 150.0;
margin = 5.0;
break;
}
// 转换为逻辑像素
final scale = 3.8; // 近似转换:1mm ≈ 3.8像素
final width = paperWidth * scale;
final height = paperHeight * scale;
final padding = margin * scale;
return Stack(
alignment: Alignment.center,
children: [
Container(
width: width,
decoration: BoxDecoration(
color: _paperColor,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 5,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 打印纸顶部
Container(
width: width,
height: height,
padding: EdgeInsets.all(padding),
decoration: _showGridLines
? BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
_paperColor,
_paperColor.withOpacity(0.98),
],
stops: const [0.0, 1.0],
),
border: Border.all(
color: Colors.grey.withOpacity(0.1),
width: 0.5,
),
)
: null,
child: Text(
_textContent,
style: const TextStyle(
fontSize: 14,
height: 1.5,
),
),
),
// 打印纸底部(撕边效果)
Container(
width: width,
height: 20,
child: CustomPaint(
painter: TearEdgePainter(),
size: Size(width, 20),
),
),
],
),
),
// 打印进度指示器
if (_isPrinting)
Container(
width: width * 0.8,
height: 40,
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.9),
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.2),
blurRadius: 5,
offset: const Offset(0, 2),
),
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'正在打印...',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
LinearProgressIndicator(
value: _printProgress,
backgroundColor: Colors.grey.withOpacity(0.3),
valueColor: const AlwaysStoppedAnimation<Color>(Colors.blue),
minHeight: 6,
borderRadius: BorderRadius.circular(3),
),
],
),
),
],
);
}
撕边效果画笔
/// 撕边效果画笔
class TearEdgePainter extends CustomPainter {
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.grey.withOpacity(0.3)
..strokeWidth = 1.0
..style = PaintingStyle.fill;
final path = Path();
path.moveTo(0, 0);
// 绘制波浪形撕边效果
final waveCount = (size.width / 20).round();
final waveHeight = size.height;
for (int i = 0; i <= waveCount; i++) {
final x = i * 20.0;
final y = i % 2 == 0 ? 0.0 : waveHeight;
path.lineTo(x, y);
}
path.lineTo(size.width, 0);
path.close();
canvas.drawPath(path, paint);
}
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
打印模拟功能
/// 模拟打印
void _simulatePrint() {
setState(() {
_isPrinting = true;
_printProgress = 0.0;
});
// 重置并启动动画控制器
_animationController.reset();
_animationController.forward().then((_) {
// 动画结束后,显示打印完成提示
setState(() {
_isPrinting = false;
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('打印完成!')),
);
});
}
📱 界面设计
主界面
打印纸模拟器主界面包括以下部分:
- 顶部导航栏:显示应用名称,包含保存和分享按钮
- 设置选项栏:包含纸张类型选择、颜色选择、网格线开关和打印按钮
- 打印纸预览区:显示当前纸张预览,包括文本内容、颜色和网格线
- 文本编辑区:支持多行文本输入,实时更新打印预览
交互设计
- 纸张类型选择:通过下拉菜单实现,实时更新纸张尺寸
- 颜色选择:通过弹出对话框实现,点击颜色选项即可切换
- 网格线开关:通过Switch组件实现,实时更新网格线显示
- 文本编辑:通过TextField组件实现,实时更新打印内容
- 打印按钮:点击后开始打印动画,显示进度条
🛠️ 技术难点和解决方案
1. 多种纸张类型的实现
难点:不同纸张类型具有不同的尺寸和边距,需要动态调整界面布局。
解决方案:使用枚举定义不同纸张类型,根据选择的类型动态计算纸张尺寸和边距,并更新界面显示。
2. 撕边效果的实现
难点:实现真实的撕边效果,增强打印纸的真实感。
解决方案:使用CustomPaint自定义绘制,通过Path绘制波浪形撕边效果,模拟真实的纸张撕边。
3. 打印模拟动画
难点:实现平滑的打印动画和进度显示。
解决方案:使用AnimationController和LinearProgressIndicator,结合SnackBar实现完整的打印模拟效果。
4. 实时预览更新
难点:文本编辑时实时更新打印预览,保证界面流畅性。
解决方案:使用setState和TextField的onChanged回调,实时更新文本内容并刷新界面。
🎉 总结
项目成果
本项目成功实现了一个支持自定义的打印纸生成器,具有以下特点:
- ✅ 支持多种打印纸类型(A4纸、收据纸、标签纸)
- ✅ 支持自定义纸张颜色
- ✅ 支持网格线显示开关
- ✅ 支持多行文本编辑
- ✅ 具有打印模拟效果
- ✅ 实现了真实的撕边效果
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐


所有评论(0)