鸿蒙flutter第三方库适配 - 图片拼图工具
运行效果图图片拼图工具是一款创意十足的图片拼接应用,帮助用户将多张图片拼接成精美的拼图作品。应用提供11种拼图模板,支持2-9张图片的灵活组合,用户可自定义边框样式、圆角效果、拼图比例和背景颜色,打造独一无二的拼图效果。完成的拼图可一键保存到相册或分享到社交平台,让美好瞬间更加精彩。应用以活力的粉色为主色调,象征创意与活力。涵盖创建、模板、历史、设置四大模块。用户可以轻松选择图片、挑选模板、调整样
图片拼图工具应用
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
适配的第三方库地址:
- image_picker - 图片选择
- image - 图片处理(纯Dart库)
- image_gallery_saver - 图片保存
- share_plus - 分享功能
一、项目概述
运行效果图




1.1 应用简介
图片拼图工具是一款创意十足的图片拼接应用,帮助用户将多张图片拼接成精美的拼图作品。应用提供11种拼图模板,支持2-9张图片的灵活组合,用户可自定义边框样式、圆角效果、拼图比例和背景颜色,打造独一无二的拼图效果。完成的拼图可一键保存到相册或分享到社交平台,让美好瞬间更加精彩。
应用以活力的粉色为主色调,象征创意与活力。涵盖创建、模板、历史、设置四大模块。用户可以轻松选择图片、挑选模板、调整样式、生成拼图,实现图片的创意组合。
1.2 核心功能
| 功能模块 | 功能描述 | 实现方式 |
|---|---|---|
| 图片选择 | 从相册选择多张图片 | image_picker |
| 模板选择 | 11种拼图模板可选 | 模板枚举 |
| 边框样式 | 无边框、细、中、粗边框 | 样式设置 |
| 圆角效果 | 直角到圆形五种圆角 | 样式设置 |
| 拼图比例 | 正方形、4:3、16:9等 | 比例设置 |
| 背景颜色 | 多种背景色可选 | 颜色选择 |
| 图片排序 | 拖拽调整图片顺序 | ReorderableListView |
| 保存相册 | 将拼图保存到相册 | image_gallery_saver |
| 分享功能 | 分享拼图到社交平台 | share_plus |
1.3 拼图模板定义
| 序号 | 模板名称 | 图片数 | 行数 | 列数 | 描述 |
|---|---|---|---|---|---|
| 1 | 2宫格 | 2 | 1 | 2 | 横向排列2张 |
| 2 | 3宫格 | 3 | 1 | 3 | 横向排列3张 |
| 3 | 4宫格 | 4 | 2 | 2 | 经典2×2布局 |
| 4 | 6宫格 | 6 | 2 | 3 | 2×3布局 |
| 5 | 9宫格 | 9 | 3 | 3 | 经典3×3布局 |
| 6 | 横向2图 | 2 | 1 | 2 | 横向拼接 |
| 7 | 横向3图 | 3 | 1 | 3 | 横向拼接 |
| 8 | 纵向2图 | 2 | 2 | 1 | 纵向拼接 |
| 9 | 纵向3图 | 3 | 3 | 1 | 纵向拼接 |
| 10 | 左1右2 | 3 | 2 | 2 | 左侧大图右侧小图 |
| 11 | 上1下2 | 3 | 2 | 2 | 上方大图下方小图 |
1.4 边框样式定义
| 序号 | 样式名称 | 宽度 | 描述 |
|---|---|---|---|
| 1 | 无边框 | 0px | 图片无缝拼接 |
| 2 | 细边框 | 2px | 细线分隔 |
| 3 | 中等 | 4px | 适中边框 |
| 4 | 粗边框 | 8px | 明显分隔 |
1.5 圆角样式定义
| 序号 | 样式名称 | 圆角 | 描述 |
|---|---|---|---|
| 1 | 直角 | 0px | 锐利边角 |
| 2 | 小圆角 | 8px | 微微圆润 |
| 3 | 中圆角 | 16px | 适中圆角 |
| 4 | 大圆角 | 32px | 明显圆角 |
| 5 | 圆形 | 100px | 完全圆形 |
1.6 拼图比例定义
| 序号 | 比例名称 | 比例值 | 适用场景 |
|---|---|---|---|
| 1 | 正方形 | 1:1 | Instagram、头像 |
| 2 | 4:3 | 4:3 | 传统照片 |
| 3 | 3:4 | 3:4 | 竖版照片 |
| 4 | 16:9 | 16:9 | 宽屏展示 |
| 5 | 9:16 | 9:16 | 手机壁纸 |
1.7 技术栈
| 技术领域 | 技术选型 | 版本要求 |
|---|---|---|
| 开发框架 | Flutter | >= 3.0.0 |
| 编程语言 | Dart | >= 2.17.0 |
| 设计规范 | Material Design 3 | - |
| 图片选择 | image_picker | >= 1.0.4 |
| 图片处理 | image | >= 4.1.7 |
| 图片保存 | image_gallery_saver | >= 2.0.3 |
| 分享功能 | share_plus | >= 7.2.2 |
| 目标平台 | 鸿蒙OS / Android / iOS | API 21+ |
1.8 项目结构
lib/
└── main_image_collage.dart
├── ImageCollageApp # 应用入口
├── CollageTemplate # 拼图模板枚举
├── BorderStyle # 边框样式枚举
├── CornerStyle # 圆角样式枚举
├── CollageRatio # 拼图比例枚举
├── CollageImage # 图片信息模型
├── ImageCollageHomePage # 主页面(底部导航)
├── _buildCreatePage # 创建页面
├── _buildTemplatesPage # 模板页面
├── _buildHistoryPage # 历史记录页
├── _buildSettingsPage # 设置页
├── _generateCollageImage # 生成拼图图片
└── _buildCollageGrid # 拼图网格预览
二、系统架构
2.1 整体架构图
2.2 类图设计
2.3 页面导航流程
2.4 拼图生成流程
三、核心模块设计
3.1 数据模型设计
3.1.1 拼图模板枚举 (CollageTemplate)
enum CollageTemplate {
grid2(label: '2宫格', count: 2, rows: 1, cols: 2, icon: Icons.grid_view),
grid3(label: '3宫格', count: 3, rows: 1, cols: 3, icon: Icons.view_week),
grid4(label: '4宫格', count: 4, rows: 2, cols: 2, icon: Icons.grid_4x4),
grid6(label: '6宫格', count: 6, rows: 2, cols: 3, icon: Icons.apps),
grid9(label: '9宫格', count: 9, rows: 3, cols: 3, icon: Icons.apps_outlined),
// ... 其他模板
final String label;
final int count;
final int rows;
final int cols;
final IconData icon;
const CollageTemplate({
required this.label,
required this.count,
required this.rows,
required this.cols,
required this.icon,
});
}
3.1.2 边框样式枚举 (BorderStyle)
enum BorderStyle {
none(label: '无边框', width: 0),
thin(label: '细边框', width: 2),
medium(label: '中等', width: 4),
thick(label: '粗边框', width: 8);
final String label;
final double width;
const BorderStyle({
required this.label,
required this.width,
});
}
3.1.3 图片信息模型 (CollageImage)
class CollageImage {
final String id;
final File file;
final String name;
final int order;
const CollageImage({
required this.id,
required this.file,
required this.name,
required this.order,
});
}
3.1.4 模板使用分布
3.2 页面结构设计
3.2.1 主页面布局
3.2.2 创建页结构
3.2.3 模板页结构
3.3 拼图生成逻辑
3.4 图片排序逻辑
四、UI设计规范
4.1 配色方案
应用以活力的粉色为主色调,象征创意与活力:
| 颜色类型 | 色值 | 用途 |
|---|---|---|
| 主色 | #E91E63 (Pink) | 导航、主题元素 |
| 辅助色 | #F48FB1 | 次要按钮 |
| 第三色 | #FCE4EC | 背景装饰 |
| 强调色 | #C2185B | 重要操作 |
| 背景色 | #FAFAFA | 页面背景 |
| 卡片背景 | #FFFFFF | 信息卡片 |
| 成功色 | #4CAF50 | 保存成功 |
| 分享色 | #2196F3 | 分享按钮 |
4.2 模板配色
| 模板类型 | 背景色建议 | 适用场景 |
|---|---|---|
| 4宫格 | 白色/黑色 | 日常拼图 |
| 9宫格 | 白色 | 社交分享 |
| 横向拼接 | 黑色 | 风景展示 |
| 纵向拼接 | 白色 | 人物展示 |
| 特殊模板 | 灰色 | 创意拼图 |
4.3 字体规范
| 元素 | 字号 | 字重 | 颜色 |
|---|---|---|---|
| 页面标题 | 24px | Bold | 主色 |
| 模板名称 | 14px | Bold | 黑色 |
| 图片数量 | 12px | Regular | 灰色 |
| 按钮文字 | 14px | Medium | 白色 |
| 提示文字 | 12px | Regular | 灰色 |
4.4 组件规范
4.4.1 模板选择器
┌─────────────────────────────────────┐
│ 选择模板 3/4 │
│ │
│ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
│ │ ▦ │ │ ▦ │ │ ▦ │ │ ▦ │ │ ▦ │ │
│ │2格│ │3格│ │4格│ │6格│ │9格│ │
│ └───┘ └───┘ └───┘ └───┘ └───┘ │
└─────────────────────────────────────┘
4.4.2 拼图预览
┌─────────────────────────────────────┐
│ 拼图预览 │
│ │
│ ┌─────────────────────────────┐ │
│ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ 图1 │ │ 图2 │ │ 图3 │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ └─────┘ └─────┘ └─────┘ │ │
│ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ 图4 │ │ 图5 │ │ 图6 │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ └─────┘ └─────┘ └─────┘ │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
4.4.3 图片选择器
┌─────────────────────────────────────┐
│ 已选图片 [添加] [清空] │
│ │
│ ≡ [图片] image_001.jpg ✕ │
│ 位置 1 │
│ │
│ ≡ [图片] image_002.jpg ✕ │
│ 位置 2 │
│ │
│ ≡ [图片] image_003.jpg ✕ │
│ 位置 3 │
└─────────────────────────────────────┘
4.4.4 样式设置
┌─────────────────────────────────────┐
│ 样式设置 │
│ │
│ 边框样式 │
│ [无边框] [细边框] [中等] [粗边框] │
│ │
│ 圆角样式 │
│ [直角] [小圆角] [中圆角] [大圆角] [圆形]│
│ │
│ 拼图比例 │
│ [正方形] [4:3] [3:4] [16:9] [9:16] │
│ │
│ 背景颜色 │
│ ● ○ ○ ○ ○ │
│ 黑色 白色 灰色 蓝色 粉色 │
└─────────────────────────────────────┘
4.4.5 操作按钮
┌─────────────────────────────────────┐
│ │
│ [💾 保存到相册] │
│ │
│ [📤 分享拼图] │
│ │
└─────────────────────────────────────┘
五、核心功能实现
5.1 图片选择实现
Future<void> _pickImages() async {
try {
final remaining = _selectedTemplate.count - _selectedImages.length;
if (remaining <= 0) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('已达到模板最大图片数')),
);
return;
}
final List<XFile> images = await _imagePicker.pickMultiImage();
if (images.isEmpty) return;
int addedCount = 0;
for (var image in images) {
if (_selectedImages.length >= _selectedTemplate.count) break;
final collageImage = CollageImage(
id: 'img_${DateTime.now().millisecondsSinceEpoch}_${image.name}',
file: File(image.path),
name: image.name,
order: _selectedImages.length,
);
setState(() {
_selectedImages.add(collageImage);
});
addedCount++;
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('选择图片失败: $e')),
);
}
}
5.2 拼图生成实现
Future<img.Image?> _generateCollageImage() async {
if (_selectedImages.isEmpty) return null;
final outputSize = 1200;
final borderPx = _borderStyle.width.toInt();
final totalWidth = outputSize;
final totalHeight = _collageRatio.ratio >= 1
? (outputSize / _collageRatio.ratio).round()
: outputSize;
final result = img.Image(width: totalWidth, height: totalHeight);
// 填充背景
final bgColor = img.ColorRgba8(
_backgroundColor.red,
_backgroundColor.green,
_backgroundColor.blue,
255,
);
img.fill(result, color: bgColor);
final template = _selectedTemplate;
final cols = template.cols;
final rows = template.rows;
final cellWidth = (totalWidth - borderPx * (cols + 1)) ~/ cols;
final cellHeight = (totalHeight - borderPx * (rows + 1)) ~/ rows;
for (int i = 0; i < _selectedImages.length && i < template.count; i++) {
final imageItem = _selectedImages[i];
final bytes = await imageItem.file.readAsBytes();
final decodedImage = img.decodeImage(bytes);
if (decodedImage == null) continue;
final row = i ~/ cols;
final col = i % cols;
final resizedImage = img.copyResize(
decodedImage,
width: cellWidth,
height: cellHeight,
);
final x = borderPx + col * (cellWidth + borderPx);
final y = borderPx + row * (cellHeight + borderPx);
img.compositeImage(result, resizedImage, dstX: x, dstY: y);
}
return result;
}
5.3 图片排序实现
void _reorderImages(int oldIndex, int newIndex) {
setState(() {
if (newIndex > oldIndex) {
newIndex -= 1;
}
final item = _selectedImages.removeAt(oldIndex);
_selectedImages.insert(newIndex, item);
// 更新顺序
for (int i = 0; i < _selectedImages.length; i++) {
_selectedImages[i] = CollageImage(
id: _selectedImages[i].id,
file: _selectedImages[i].file,
name: _selectedImages[i].name,
order: i,
);
}
});
}
5.4 保存拼图实现
Future<void> _saveCollage() async {
if (_selectedImages.isEmpty) return;
setState(() {
_isProcessing = true;
});
try {
final collageImage = await _generateCollageImage();
if (collageImage == null) {
throw Exception('生成拼图失败');
}
final tempDir = await getTemporaryDirectory();
final filePath = '${tempDir.path}/collage_${DateTime.now().millisecondsSinceEpoch}.png';
final file = File(filePath);
await file.writeAsBytes(img.encodePng(collageImage));
final bytes = await file.readAsBytes();
final result = await ImageGallerySaver.saveImage(
bytes,
quality: 100,
name: 'collage_${DateTime.now().millisecondsSinceEpoch}',
);
setState(() {
_isProcessing = false;
});
if (result['isSuccess'] == true) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('拼图已保存到相册')),
);
}
} catch (e) {
setState(() {
_isProcessing = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('保存失败: $e')),
);
}
}
5.5 分享拼图实现
Future<void> _shareCollage() async {
if (_selectedImages.isEmpty) return;
setState(() {
_isProcessing = true;
});
try {
final collageImage = await _generateCollageImage();
if (collageImage == null) {
throw Exception('生成拼图失败');
}
final tempDir = await getTemporaryDirectory();
final filePath = '${tempDir.path}/collage_share_${DateTime.now().millisecondsSinceEpoch}.png';
final file = File(filePath);
await file.writeAsBytes(img.encodePng(collageImage));
setState(() {
_isProcessing = false;
});
await Share.shareXFiles(
[XFile(filePath)],
text: '分享我的拼图',
);
} catch (e) {
setState(() {
_isProcessing = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('分享失败: $e')),
);
}
}
六、交互设计
6.1 图片选择流程
6.2 拼图生成流程
6.3 样式调整流程
七、扩展功能规划
7.1 后续版本规划
7.2 功能扩展建议
7.2.1 滤镜效果
滤镜功能:
- 亮度对比度调整
- 色彩饱和度
- 复古滤镜
- 黑白滤镜
7.2.2 文字贴纸
贴纸功能:
- 添加文字
- 表情贴纸
- 日期水印
- 自定义贴纸
7.2.3 自由拼图
自由功能:
- 自由拖拽位置
- 自由缩放大小
- 图层管理
- 自定义模板保存
八、注意事项
8.1 开发注意事项
-
内存管理:处理大图片时注意内存释放
-
权限申请:确保存储权限正确申请
-
图片质量:输出高质量拼图图片
-
模板适配:特殊模板需要单独处理布局逻辑
-
用户体验:实时预览拼图效果
8.2 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 图片选择失败 | 权限未授予 | 引导用户授权 |
| 拼图生成失败 | 内存不足 | 分批处理图片 |
| 保存失败 | 存储空间不足 | 提示清理空间 |
| 图片变形 | 比例不匹配 | 使用cover模式 |
| 预览卡顿 | 图片过大 | 压缩预览图 |
8.3 使用技巧
🖼️ 图片拼图工具使用技巧 🖼️
选择技巧
- 根据图片数量选择模板
- 注意图片比例一致性
- 选择合适的拼图比例
- 预览效果再保存
排版技巧
- 重要图片放显眼位置
- 色彩搭配要协调
- 适当使用边框分隔
- 背景色与图片呼应
分享技巧
- 选择适合平台的比例
- 注意图片清晰度
- 添加文字说明
- 选择合适时机分享
九、运行说明
9.1 环境要求
| 环境 | 版本要求 |
|---|---|
| Flutter SDK | >= 3.0.0 |
| Dart SDK | >= 2.17.0 |
| 鸿蒙OS | API 21+ |
| Android | API 21+ |
| iOS | 12.0+ |
9.2 依赖配置
在 pubspec.yaml 中添加以下依赖:
dependencies:
flutter:
sdk: flutter
image_picker: ^1.0.4
image: ^4.1.7
image_gallery_saver: ^2.0.3
share_plus: ^7.2.2
path_provider: ^2.1.4
9.3 运行命令
# 查看可用设备
flutter devices
# 运行到Web服务器
flutter run -d web-server -t lib/main_image_collage.dart --web-port 8148
# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 lib/main_image_collage.dart
# 运行到Android设备
flutter run -d android lib/main_image_collage.dart
# 代码分析
flutter analyze lib/main_image_collage.dart
9.4 权限配置
Android权限 (android/app/src/main/AndroidManifest.xml)
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
iOS权限 (ios/Runner/Info.plist)
<key>NSPhotoLibraryUsageDescription</key>
<string>需要相册权限选择和保存图片</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>需要相册权限保存拼图</string>
十、总结
图片拼图工具应用通过整合图片选择、模板选择、样式设置、拼图生成、保存分享等功能,为用户提供了一站式的图片拼接解决方案。应用支持11种拼图模板,涵盖2-9张图片的灵活组合,用户可自定义边框样式、圆角效果、拼图比例和背景颜色,打造独一无二的拼图效果。
核心功能涵盖图片选择、模板选择、边框样式、圆角效果、拼图比例、背景颜色、图片排序、保存相册、分享功能九大模块。用户可以轻松选择图片、挑选模板、调整样式、生成拼图,实现图片的创意组合。
应用采用 Material Design 3 设计规范,以活力的粉色为主色调,象征创意与活力。通过本应用,希望能够帮助用户更高效地进行图片拼图创作,让美好瞬间更加精彩。
图片拼图工具——让创意无限可能
更多推荐


所有评论(0)