Flutter for OpenHarmony 二维码扫描App实战 - 二维码预览实现
二维码预览页面是生成流程的最后一步,用户在这里可以看到生成的二维码,并进行保存、分享等操作。这篇文章介绍二维码预览页面的实现,包括二维码显示、内容信息展示、保存分享功能等。
二维码预览页面是生成流程的最后一步,用户在这里可以看到生成的二维码,并进行保存、分享等操作。这篇文章介绍二维码预览页面的实现,包括二维码显示、内容信息展示、保存分享功能等。
二维码预览的设计思路
预览页面需要展示以下内容:
二维码图片:生成的二维码图片,是页面的核心内容
内容信息:二维码编码的原始内容,方便用户确认
类型标签:二维码的类型,如网址、文本、WiFi 等
操作按钮:保存到相册、分享、重新生成等操作
页面布局采用上下结构,上方是二维码和信息,下方是操作按钮。
QrPreviewView 的基础结构
先来看文件的导入和类定义:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../data/models/qr_record.dart';
import '../../routes/app_pages.dart';
class QrPreviewView extends StatelessWidget {
const QrPreviewView({super.key});
导入了必要的包。QrPreviewView 使用 StatelessWidget,因为页面状态主要来自传入的参数,不需要本地状态管理。
获取传入的记录
build 方法开始时获取传入的记录:
Widget build(BuildContext context) {
final record = Get.arguments as QrRecord;
return Scaffold(
appBar: AppBar(
title: const Text('二维码预览'),
actions: [
IconButton(
icon: const Icon(Icons.palette),
onPressed: () => Get.toNamed(Routes.QR_STYLE),
tooltip: '样式设置',
),
],
),
Get.arguments 获取路由传递的参数,这里是 QrRecord 对象。AppBar 的 actions 中有一个样式设置按钮,点击可以跳转到样式设置页面。
页面主体布局
body 使用 SingleChildScrollView 包裹:
body: SingleChildScrollView(
padding: EdgeInsets.all(16.w),
child: Column(
children: [
SingleChildScrollView 让页面内容可以滚动,适应不同屏幕尺寸。padding 设置四周 16.w 的内边距。
二维码显示区域
二维码显示区域使用 Card 包裹:
Card(
child: Padding(
padding: EdgeInsets.all(24.w),
child: Column(
children: [
Container(
width: 200.w,
height: 200.w,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.r),
border: Border.all(color: Colors.grey[300]!),
),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.qr_code_2, size: 120.sp, color: Colors.black87),
SizedBox(height: 8.h),
Text(
record.typeLabel,
style: TextStyle(fontSize: 12.sp, color: Colors.grey),
),
],
),
),
),
Card 提供卡片效果,内部 padding 为 24.w。Container 设置固定的宽高 200.w,白色背景,圆角边框。
内部显示二维码图标和类型标签。在实际项目中,这里应该使用 qr_flutter 等库生成真实的二维码图片。
生成成功提示
二维码下方显示生成成功的提示:
SizedBox(height: 16.h),
Text(
'二维码已生成',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
),
),
],
),
),
),
SizedBox(height: 16.h),
简单的文字提示,让用户知道二维码已经生成成功。
内容信息卡片
显示二维码编码的内容:
Card(
child: Padding(
padding: EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.info_outline, size: 20.sp),
SizedBox(width: 8.w),
Text(
'二维码内容',
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w600,
),
),
],
),
SizedBox(height: 8.h),
Text(
record.content,
style: TextStyle(fontSize: 12.sp, color: Colors.grey[700]),
maxLines: 5,
overflow: TextOverflow.ellipsis,
),
],
),
),
),
SizedBox(height: 24.h),
Row 显示图标和标题。Text 显示内容,限制最多 5 行,超出部分用省略号截断。
操作按钮区域
底部是保存和分享按钮:
Row(
children: [
Expanded(
child: OutlinedButton.icon(
onPressed: () {
Get.snackbar('成功', '已保存到相册',
snackPosition: SnackPosition.BOTTOM);
},
icon: const Icon(Icons.save_alt),
label: const Text('保存'),
style: OutlinedButton.styleFrom(
minimumSize: Size(0, 48.h),
),
),
),
SizedBox(width: 12.w),
Expanded(
child: OutlinedButton.icon(
onPressed: () {
Get.snackbar('提示', '分享功能',
snackPosition: SnackPosition.BOTTOM);
},
icon: const Icon(Icons.share),
label: const Text('分享'),
style: OutlinedButton.styleFrom(
minimumSize: Size(0, 48.h),
),
),
),
],
),
Row 让两个按钮水平排列,Expanded 让它们平分宽度。OutlinedButton.icon 是带图标的描边按钮。
生成新的按钮
最下方是生成新的按钮:
SizedBox(height: 12.h),
SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
onPressed: () => Get.back(),
icon: const Icon(Icons.add),
label: const Text('生成新的'),
style: ElevatedButton.styleFrom(
minimumSize: Size(0, 48.h),
backgroundColor: Theme.of(context).primaryColor,
foregroundColor: Colors.white,
),
),
),
],
),
),
);
}
}
ElevatedButton.icon 是带图标的凸起按钮,点击后返回上一页,用户可以生成新的二维码。
真实二维码生成
使用 qr_flutter 库生成真实的二维码:
import 'package:qr_flutter/qr_flutter.dart';
Widget _buildQrImage(QrRecord record) {
return QrImageView(
data: record.content,
version: QrVersions.auto,
size: 200.w,
backgroundColor: Colors.white,
errorCorrectionLevel: QrErrorCorrectLevel.M,
embeddedImage: record.logoPath != null
? FileImage(File(record.logoPath!))
: null,
embeddedImageStyle: QrEmbeddedImageStyle(
size: Size(40.w, 40.w),
),
);
}
QrImageView 是 qr_flutter 提供的二维码组件。data 是要编码的内容,version 设为 auto 自动选择版本,size 是二维码大小。
errorCorrectionLevel 设置纠错级别,M 级别可以恢复约 15% 的数据丢失。embeddedImage 可以在二维码中心嵌入 Logo。
保存到相册
实现保存到相册的功能:
import 'dart:ui' as ui;
import 'package:image_gallery_saver/image_gallery_saver.dart';
Future<void> _saveToGallery(QrRecord record) async {
// 显示加载对话框
Get.dialog(
const Center(child: CircularProgressIndicator()),
barrierDismissible: false,
);
try {
// 生成二维码图片
final qrPainter = QrPainter(
data: record.content,
version: QrVersions.auto,
errorCorrectionLevel: QrErrorCorrectLevel.M,
);
final picData = await qrPainter.toImageData(300);
if (picData == null) {
Get.back();
Get.snackbar('错误', '生成图片失败', snackPosition: SnackPosition.BOTTOM);
return;
}
// 保存到相册
final result = await ImageGallerySaver.saveImage(
picData.buffer.asUint8List(),
quality: 100,
name: 'qr_${DateTime.now().millisecondsSinceEpoch}',
);
Get.back();
if (result['isSuccess']) {
Get.snackbar('成功', '已保存到相册', snackPosition: SnackPosition.BOTTOM);
} else {
Get.snackbar('错误', '保存失败', snackPosition: SnackPosition.BOTTOM);
}
} catch (e) {
Get.back();
Get.snackbar('错误', '保存失败: $e', snackPosition: SnackPosition.BOTTOM);
}
}
使用 QrPainter 生成二维码图片数据,然后使用 image_gallery_saver 插件保存到相册。
分享功能
实现分享功能:
import 'package:share_plus/share_plus.dart';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
Future<void> _shareQr(QrRecord record) async {
Get.dialog(
const Center(child: CircularProgressIndicator()),
barrierDismissible: false,
);
try {
// 生成二维码图片
final qrPainter = QrPainter(
data: record.content,
version: QrVersions.auto,
errorCorrectionLevel: QrErrorCorrectLevel.M,
);
final picData = await qrPainter.toImageData(300);
if (picData == null) {
Get.back();
Get.snackbar('错误', '生成图片失败', snackPosition: SnackPosition.BOTTOM);
return;
}
// 保存到临时文件
final directory = await getTemporaryDirectory();
final file = File('${directory.path}/qr_share.png');
await file.writeAsBytes(picData.buffer.asUint8List());
Get.back();
// 分享
await Share.shareXFiles(
[XFile(file.path)],
text: '扫描二维码查看: ${record.typeLabel}',
);
} catch (e) {
Get.back();
Get.snackbar('错误', '分享失败: $e', snackPosition: SnackPosition.BOTTOM);
}
}
先将二维码保存到临时文件,然后使用 share_plus 插件分享。
复制内容
提供复制二维码内容的功能:
import 'package:flutter/services.dart';
void _copyContent(String content) {
Clipboard.setData(ClipboardData(text: content));
Get.snackbar('成功', '已复制到剪贴板', snackPosition: SnackPosition.BOTTOM);
}
使用 Clipboard 复制内容到剪贴板。
收藏功能
添加收藏按钮:
Widget _buildFavoriteButton(QrRecord record) {
final historyService = Get.find<QrHistoryService>();
return Obx(() {
final isFavorite = historyService.favorites.any((e) => e.id == record.id);
return IconButton(
icon: Icon(
isFavorite ? Icons.star : Icons.star_border,
color: Colors.amber,
),
onPressed: () {
historyService.toggleFavorite(record);
Get.snackbar(
isFavorite ? '已取消收藏' : '已收藏',
'',
snackPosition: SnackPosition.BOTTOM,
);
},
);
});
}
使用 Obx 监听收藏状态变化,点击切换收藏状态。
二维码样式应用
应用用户设置的样式:
Widget _buildStyledQr(QrRecord record) {
final controller = Get.find<GenerateController>();
return Obx(() => QrImageView(
data: record.content,
version: QrVersions.auto,
size: controller.qrSize.value,
backgroundColor: controller.bgColor.value,
eyeStyle: QrEyeStyle(
eyeShape: QrEyeShape.square,
color: controller.qrColor.value,
),
dataModuleStyle: QrDataModuleStyle(
dataModuleShape: QrDataModuleShape.square,
color: controller.qrColor.value,
),
embeddedImage: controller.hasLogo.value && controller.logoPath.value.isNotEmpty
? FileImage(File(controller.logoPath.value))
: null,
embeddedImageStyle: QrEmbeddedImageStyle(
size: Size(40.w, 40.w),
),
));
}
从 GenerateController 获取样式设置,应用到二维码生成。
打印功能
提供打印二维码的功能:
import 'package:printing/printing.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
Future<void> _printQr(QrRecord record) async {
final doc = pw.Document();
// 生成二维码图片
final qrPainter = QrPainter(
data: record.content,
version: QrVersions.auto,
);
final picData = await qrPainter.toImageData(300);
if (picData == null) {
Get.snackbar('错误', '生成图片失败', snackPosition: SnackPosition.BOTTOM);
return;
}
final image = pw.MemoryImage(picData.buffer.asUint8List());
doc.addPage(
pw.Page(
build: (context) => pw.Center(
child: pw.Column(
mainAxisAlignment: pw.MainAxisAlignment.center,
children: [
pw.Image(image, width: 200, height: 200),
pw.SizedBox(height: 20),
pw.Text(record.typeLabel),
pw.SizedBox(height: 10),
pw.Text(
record.content,
style: const pw.TextStyle(fontSize: 10),
maxLines: 3,
),
],
),
),
),
);
await Printing.layoutPdf(
onLayout: (format) async => doc.save(),
);
}
使用 printing 和 pdf 插件生成 PDF 并打印。
更多操作菜单
在 AppBar 添加更多操作:
PopupMenuButton<String>(
onSelected: (value) {
switch (value) {
case 'copy':
_copyContent(record.content);
break;
case 'print':
_printQr(record);
break;
case 'edit':
// 返回编辑页面
Get.back(result: record);
break;
}
},
itemBuilder: (context) => [
const PopupMenuItem(value: 'copy', child: Text('复制内容')),
const PopupMenuItem(value: 'print', child: Text('打印')),
const PopupMenuItem(value: 'edit', child: Text('编辑')),
],
),
提供复制、打印、编辑等更多操作。
二维码信息详情
显示更详细的二维码信息:
Widget _buildDetailInfo(QrRecord record) {
return Card(
child: Padding(
padding: EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildInfoRow('类型', record.typeLabel),
_buildInfoRow('创建时间', _formatDateTime(record.createdAt)),
_buildInfoRow('内容长度', '${record.content.length} 字符'),
_buildInfoRow('二维码版本', _getQrVersion(record.content)),
],
),
),
);
}
Widget _buildInfoRow(String label, String value) {
return Padding(
padding: EdgeInsets.only(bottom: 8.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(label, style: TextStyle(fontSize: 13.sp, color: Colors.grey)),
Text(value, style: TextStyle(fontSize: 13.sp)),
],
),
);
}
String _getQrVersion(String content) {
final length = content.length;
if (length <= 25) return '版本 1';
if (length <= 47) return '版本 2';
if (length <= 77) return '版本 3';
if (length <= 114) return '版本 4';
return '版本 5+';
}
显示类型、创建时间、内容长度、二维码版本等信息。
小结
二维码预览页面是生成流程的最后一步,需要清晰展示生成的二维码,并提供便捷的保存、分享、打印等操作。
页面使用 Card 组件组织内容,二维码显示区域突出,操作按钮易于点击。收藏功能让用户可以保存常用的二维码,样式设置让用户可以自定义二维码外观。
一个好的预览页面应该让用户一眼就能确认二维码内容是否正确,并快速完成后续操作。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐
所有评论(0)