Flutter for OpenHarmony 二维码扫描App实战 - 生成主界面实现
这篇文章介绍了二维码生成界面的设计与实现。界面采用网格布局展示9种二维码类型,每种类型使用不同颜色和图标区分。主要功能包括类型选择、快速生成入口和样式设置,通过GetX框架管理状态,使用StatelessWidget保持视图层简洁。网格卡片点击跳转到对应生成页面,整体设计注重视觉区分度和用户体验。
二维码生成是扫码应用的另一个核心功能。用户不仅需要扫描别人的二维码,也需要生成自己的二维码分享给别人。这篇文章介绍生成主界面的实现,包括二维码类型选择、快速生成入口和样式设置入口。
生成界面的设计思路
生成界面需要展示多种二维码类型供用户选择,我采用了网格布局来展示这些选项。每种类型用一个卡片表示,包含图标和名称,点击后跳转到对应的生成页面。
除了类型选择,还提供了快速生成入口,用户可以直接输入文本或网址快速生成二维码,不需要先选择类型。底部还有样式设置入口,让用户可以自定义二维码的颜色、大小和 Logo。
GenerateView 的基础结构
先来看文件的导入和类定义:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../routes/app_pages.dart';
import 'generate_controller.dart';
class GenerateView extends StatelessWidget {
const GenerateView({super.key});
导入了 Flutter 的 material 组件库、GetX 框架、flutter_screenutil 屏幕适配库,以及路由配置和生成控制器。
GenerateView 使用 StatelessWidget,状态管理交给 GenerateController 处理。这种分离让视图层保持简洁,业务逻辑集中在控制器中。
控制器的初始化
build 方法开始时初始化控制器:
Widget build(BuildContext context) {
Get.put(GenerateController());
return Scaffold(
appBar: AppBar(
title: const Text('生成二维码'),
automaticallyImplyLeading: false,
actions: [
IconButton(
icon: const Icon(Icons.history),
onPressed: () => Get.toNamed(Routes.GENERATE_HISTORY),
),
],
),
Get.put 创建 GenerateController 实例并注册到依赖容器中。这样在子页面中可以通过 Get.find 获取同一个控制器实例,实现状态共享。
AppBar 的 title 设置为"生成二维码"。automaticallyImplyLeading 设为 false 隐藏返回按钮,因为这是底部导航的一个 Tab 页。actions 中放了一个历史记录按钮,点击跳转到生成历史页面。
页面主体的布局
body 使用 SingleChildScrollView 包裹,支持内容超出屏幕时滚动:
body: SingleChildScrollView(
padding: EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'选择二维码类型',
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w600,
),
),
SizedBox(height: 16.h),
SingleChildScrollView 让整个页面可以滚动,适合内容较多的页面。padding 设置四周 16.w 的内边距。
Column 的 crossAxisAlignment 设为 start,让子组件左对齐。第一个元素是标题文字"选择二维码类型",字号 18.sp,字重 w600 表示半粗体。SizedBox 添加 16.h 的垂直间距。
二维码类型网格
使用 GridView.count 创建固定列数的网格:
GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 3,
mainAxisSpacing: 12.h,
crossAxisSpacing: 12.w,
childAspectRatio: 1,
children: [
_QrTypeCard(
icon: Icons.text_fields,
label: '文本',
color: Colors.blue,
onTap: () => Get.toNamed(Routes.TEXT_QR),
),
shrinkWrap 设为 true 让 GridView 根据内容自适应高度,而不是占满可用空间。physics 设为 NeverScrollableScrollPhysics 禁用 GridView 自身的滚动,因为外层已经有 SingleChildScrollView 了。
crossAxisCount 设为 3 表示每行 3 个卡片。mainAxisSpacing 和 crossAxisSpacing 分别设置垂直和水平间距。childAspectRatio 设为 1 表示每个卡片是正方形。
第一个卡片是文本类型,使用 Icons.text_fields 图标,蓝色主题,点击跳转到文本二维码生成页面。
更多二维码类型
网格中包含 9 种二维码类型:
_QrTypeCard(
icon: Icons.link,
label: '网址',
color: Colors.green,
onTap: () => Get.toNamed(Routes.URL_QR),
),
_QrTypeCard(
icon: Icons.wifi,
label: 'WiFi',
color: Colors.orange,
onTap: () => Get.toNamed(Routes.WIFI_QR),
),
_QrTypeCard(
icon: Icons.person,
label: '联系人',
color: Colors.purple,
onTap: () => Get.toNamed(Routes.CONTACT_QR),
),
每种类型使用不同的图标和颜色,方便用户快速识别。网址用绿色链接图标,WiFi 用橙色无线图标,联系人用紫色人物图标。
这种设计让用户一眼就能找到需要的类型,不需要阅读文字就能通过颜色和图标区分。
继续添加类型卡片
剩余的类型卡片:
_QrTypeCard(
icon: Icons.email,
label: '邮箱',
color: Colors.red,
onTap: () => Get.toNamed(Routes.EMAIL_QR),
),
_QrTypeCard(
icon: Icons.phone,
label: '电话',
color: Colors.teal,
onTap: () => Get.toNamed(Routes.PHONE_QR),
),
_QrTypeCard(
icon: Icons.sms,
label: '短信',
color: Colors.indigo,
onTap: () => Get.toNamed(Routes.SMS_QR),
),
邮箱用红色邮件图标,电话用青色电话图标,短信用靛蓝色短信图标。每个卡片的 onTap 回调跳转到对应的生成页面。
颜色的选择考虑了视觉区分度,相邻的卡片尽量使用差异较大的颜色,避免用户混淆。
最后两个类型卡片
位置和事件类型:
_QrTypeCard(
icon: Icons.location_on,
label: '位置',
color: Colors.pink,
onTap: () => Get.toNamed(Routes.LOCATION_QR),
),
_QrTypeCard(
icon: Icons.event,
label: '事件',
color: Colors.amber,
onTap: () => Get.toNamed(Routes.EVENT_QR),
),
],
),
SizedBox(height: 24.h),
位置用粉色定位图标,事件用琥珀色日历图标。这两种类型相对不那么常用,放在最后一行。
GridView 后面添加 24.h 的间距,与下方的快速生成区域分隔开。
快速生成区域
快速生成区域使用 Card 包裹:
// 快速生成区域
Card(
child: Padding(
padding: EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'快速生成',
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.w600,
),
),
SizedBox(height: 12.h),
Card 提供了圆角和阴影效果,让这个区域在视觉上与其他内容区分开。内部使用 Padding 添加 16.w 的内边距。
标题"快速生成"使用 16.sp 字号和半粗体,比页面主标题小一号,形成层次感。
快速生成输入框
输入框让用户直接输入内容:
TextField(
decoration: InputDecoration(
hintText: '输入文本或网址',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.r),
),
suffixIcon: IconButton(
icon: const Icon(Icons.qr_code),
onPressed: () => Get.toNamed(Routes.TEXT_QR),
),
),
onSubmitted: (value) {
if (value.isNotEmpty) {
Get.toNamed(Routes.TEXT_QR, arguments: value);
}
},
),
TextField 的 decoration 设置了提示文字、边框样式和后缀图标。hintText 提示用户可以输入文本或网址。OutlineInputBorder 创建带圆角的边框。
suffixIcon 是一个二维码图标按钮,点击跳转到文本生成页面。onSubmitted 在用户按下键盘确认键时触发,如果输入不为空就跳转到文本生成页面,并通过 arguments 传递输入的内容。
样式设置入口
页面底部是样式设置入口:
],
),
),
),
SizedBox(height: 16.h),
// 样式设置入口
Card(
child: ListTile(
leading: const Icon(Icons.palette),
title: const Text('二维码样式设置'),
subtitle: const Text('自定义颜色、大小、Logo'),
trailing: const Icon(Icons.chevron_right),
onTap: () => Get.toNamed(Routes.QR_STYLE),
),
),
],
),
),
);
}
}
使用 Card 和 ListTile 组合创建一个可点击的设置入口。leading 是调色板图标,title 是主标题,subtitle 是副标题说明功能,trailing 是右箭头表示可以点击进入。
这种设计在设置类页面中很常见,用户一眼就能理解这是一个可以点击进入的入口。
_QrTypeCard 组件的定义
_QrTypeCard 是一个私有组件,封装了类型卡片的通用样式:
class _QrTypeCard extends StatelessWidget {
final IconData icon;
final String label;
final Color color;
final VoidCallback onTap;
const _QrTypeCard({
required this.icon,
required this.label,
required this.color,
required this.onTap,
});
组件接收四个必需参数:icon 是图标数据,label 是显示的文字,color 是主题颜色,onTap 是点击回调。
使用 const 构造函数可以让 Flutter 在编译时创建这些组件,提高性能。下划线前缀表示这是一个私有类,只在当前文件中使用。
_QrTypeCard 的 build 方法
build 方法返回卡片的具体结构:
Widget build(BuildContext context) {
return Card(
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(12.r),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: EdgeInsets.all(12.w),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(icon, color: color, size: 28.sp),
),
Card 提供基础的卡片样式。InkWell 添加点击效果,borderRadius 设置水波纹的圆角范围。Column 让图标和文字垂直居中排列。
图标外面包了一个圆形的 Container,背景色是主题色的 10% 透明度版本,这样既有颜色区分又不会太刺眼。图标大小 28.sp,颜色使用传入的主题色。
_QrTypeCard 的文字部分
图标下方是类型名称:
SizedBox(height: 8.h),
Text(
label,
style: TextStyle(fontSize: 12.sp, fontWeight: FontWeight.w500),
),
],
),
),
);
}
}
SizedBox 添加 8.h 的间距。Text 显示类型名称,字号 12.sp,字重 w500 表示中等粗细。
整个卡片的设计简洁明了,图标突出显示,文字作为辅助说明。用户可以通过颜色和图标快速识别不同类型。
控制器的作用
GenerateController 在这个页面中的作用主要是:
- 状态共享:子页面可以通过 Get.find 获取同一个控制器实例
- 生成逻辑:封装二维码生成的业务逻辑
- 样式管理:管理用户选择的二维码样式设置
虽然在主界面中没有直接使用控制器的方法,但在子页面中会频繁用到。
路由设计
页面中使用了多个路由常量:
- Routes.TEXT_QR:文本二维码生成页
- Routes.URL_QR:网址二维码生成页
- Routes.WIFI_QR:WiFi 二维码生成页
- Routes.CONTACT_QR:联系人二维码生成页
- Routes.EMAIL_QR:邮箱二维码生成页
- Routes.PHONE_QR:电话二维码生成页
- Routes.SMS_QR:短信二维码生成页
- Routes.LOCATION_QR:位置二维码生成页
- Routes.EVENT_QR:事件二维码生成页
- Routes.QR_STYLE:样式设置页
- Routes.GENERATE_HISTORY:生成历史页
这些路由常量定义在 app_pages.dart 中,使用常量而不是字符串可以避免拼写错误,也方便重构。
用户体验优化
生成主界面的设计考虑了以下用户体验要点:
- 快速访问:最常用的类型放在前面,快速生成入口让用户可以跳过类型选择
- 视觉区分:不同类型使用不同颜色,方便快速识别
- 层次清晰:标题、网格、快速生成、样式设置四个区域层次分明
- 滚动支持:内容较多时可以滚动,不会被截断
小结
这篇文章介绍了生成主界面的完整实现。从页面布局的设计,到类型网格的实现,再到快速生成和样式设置入口,覆盖了生成功能的入口页面。
生成主界面是用户进入生成功能的第一个页面,设计要清晰直观,让用户快速找到需要的功能。网格布局展示多种类型,快速生成入口提供便捷操作,样式设置入口满足个性化需求。这些元素组合在一起,形成了一个功能完整、体验良好的生成入口。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐

所有评论(0)