Flutter for OpenHarmony 猫咪管家App实战:个人中心模块开发详解
本文介绍了猫咪管家App个人中心页面的实现方案。页面采用StatelessWidget构建,包含三个主要模块:渐变背景的头部区域(显示用户头像、名称和猫咪数量统计)、数据统计卡片(展示猫咪、日记、喂食和支出四项关键数据)以及功能菜单区(分为"我的猫咪"和"设置与帮助"两组)。设计上注重视觉层次,通过颜色区分功能模块,使用Consumer实现数据实时更新。技术

个人中心是每个App都会有的模块,用来展示用户信息和提供各种入口。今天来实现猫咪管家的个人中心页面,包括用户头像、数据统计、功能菜单等内容。
一、页面整体架构
个人中心不需要复杂的状态管理,用 StatelessWidget 就够了:
class ProfileTab extends StatelessWidget {
const ProfileTab({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('我的'),
actions: [
IconButton(
icon: const Icon(Icons.settings),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (_) => const SettingsScreen()),
),
),
],
),
标题栏右边放了个设置按钮,点击跳转到设置页面。
这是很常见的设计模式,用户一眼就知道在哪里找设置。
页面主体用 SingleChildScrollView 包裹:
body: SingleChildScrollView(
child: Column(
children: [
_buildProfileHeader(context),
SizedBox(height: 16.h),
_buildStatisticsCard(context),
SizedBox(height: 16.h),
_buildMenuSection(context),
],
),
),
三个主要区块:头部信息、数据统计、功能菜单。
用 SizedBox 控制间距,比 Padding 更直观。
二、用户头部区域
头部用渐变背景,视觉效果更好:
Widget _buildProfileHeader(BuildContext context) {
return Container(
padding: EdgeInsets.all(20.w),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.orange, Colors.orange.shade300],
),
),
LinearGradient 创建从上到下的渐变效果。
橙色系和App主题保持一致,品牌感强。
头像和用户名:
child: Column(
children: [
CircleAvatar(
radius: 45.r,
backgroundColor: Colors.white,
child: Icon(Icons.person, size: 50.sp, color: Colors.orange),
),
SizedBox(height: 12.h),
Text(
'猫咪管家用户',
style: TextStyle(
fontSize: 20.sp,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
圆形头像用白色背景,和橙色渐变形成对比。
暂时用图标代替真实头像,后续可以加上传功能。
猫咪数量统计:
Consumer<CatProvider>(
builder: (context, provider, child) {
return Text(
'已记录 ${provider.cats.length} 只猫咪',
style: TextStyle(
fontSize: 14.sp,
color: Colors.white.withOpacity(0.9),
),
);
},
),
用 Consumer 监听数据变化,猫咪数量会实时更新。
文字用 90% 透明度的白色,比纯白柔和一些。
三、数据统计卡片
统计卡片展示关键数据:
Widget _buildStatisticsCard(BuildContext context) {
return Consumer<CatProvider>(
builder: (context, provider, child) {
return Card(
margin: EdgeInsets.symmetric(horizontal: 16.w),
child: Padding(
padding: EdgeInsets.all(16.w),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
Card 自带圆角和阴影,不用额外设置。
spaceAround 让四个统计项均匀分布。
四个统计项:
children: [
_buildStatItem('猫咪', '${provider.cats.length}', Icons.pets),
Container(width: 1, height: 40.h, color: Colors.grey[300]),
_buildStatItem('日记', '${provider.diaryEntries.length}', Icons.book),
Container(width: 1, height: 40.h, color: Colors.grey[300]),
_buildStatItem('喂食', '${provider.feedingRecords.length}', Icons.restaurant),
Container(width: 1, height: 40.h, color: Colors.grey[300]),
_buildStatItem('支出', '${provider.expenseRecords.length}', Icons.receipt),
],
用竖线分隔各个统计项,视觉上更清晰。
数据都从 Provider 获取,保证实时性。
单个统计项组件:
Widget _buildStatItem(String label, String value, IconData icon) {
return Column(
children: [
Icon(icon, color: Colors.orange, size: 24.sp),
SizedBox(height: 4.h),
Text(
value,
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.bold,
),
),
Text(
label,
style: TextStyle(
fontSize: 12.sp,
color: Colors.grey[600],
),
),
],
);
}
图标在上,数字在中,标签在下,层次分明。
数字加粗突出显示,是用户最关心的信息。
四、功能菜单区域
菜单分组展示:
Widget _buildMenuSection(BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 16.w),
child: Column(
children: [
_buildMenuCard(
'我的猫咪',
[
_MenuItem(
icon: Icons.pets,
title: '猫咪管理',
color: Colors.orange,
onTap: () => Navigator.push(context, MaterialPageRoute(
builder: (_) => const CatListScreen(),
)),
),
菜单按功能分组,"我的猫咪"和"设置与帮助"两组。
每个菜单项都有图标、标题、颜色和点击回调。
日记本入口:
_MenuItem(
icon: Icons.book,
title: '日记本',
color: Colors.blue,
onTap: () => Navigator.push(context, MaterialPageRoute(
builder: (_) => const DiaryListScreen(),
)),
),
日记本用蓝色图标,和猫咪管理的橙色区分开。
颜色的选择要有一定的逻辑,不能太随意。
设置与帮助组:
_buildMenuCard(
'设置与帮助',
[
_MenuItem(
icon: Icons.settings,
title: '设置',
color: Colors.grey,
onTap: () => Navigator.push(context, MaterialPageRoute(
builder: (_) => const SettingsScreen(),
)),
),
_MenuItem(
icon: Icons.info,
title: '关于我们',
color: Colors.teal,
onTap: () => Navigator.push(context, MaterialPageRoute(
builder: (_) => const AboutScreen(),
)),
),
],
),
设置用灰色,表示系统功能。
关于用青色,和其他颜色都不重复。
五、菜单卡片组件
卡片容器:
Widget _buildMenuCard(String title, List<_MenuItem> items) {
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.fromLTRB(16.w, 12.h, 16.w, 8.h),
child: Text(
title,
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.bold,
color: Colors.grey[700],
),
),
),
分组标题放在卡片内部顶端。
灰色加粗,不抢菜单项的视觉。
菜单项渲染:
...items.map((item) => ListTile(
leading: Container(
padding: EdgeInsets.all(8.w),
decoration: BoxDecoration(
color: item.color.withOpacity(0.1),
borderRadius: BorderRadius.circular(8.r),
),
child: Icon(item.icon, color: item.color, size: 20.sp),
),
title: Text(item.title),
trailing: Icon(Icons.chevron_right, color: Colors.grey[400]),
onTap: item.onTap,
)),
用展开运算符
...把 map 结果展开到 Column 中。
leading 用带背景色的图标,比纯图标好看。
六、菜单项数据类
定义菜单项结构:
class _MenuItem {
final IconData icon;
final String title;
final Color color;
final VoidCallback onTap;
_MenuItem({
required this.icon,
required this.title,
required this.color,
required this.onTap,
});
}
用私有类封装菜单项数据,只在当前文件使用。
required 确保所有字段都必须传值。
为什么用类而不是 Map:
类有类型检查,IDE 能自动补全。
Map 虽然灵活,但容易写错 key。
七、图标背景的设计
图标背景用主色的 10% 透明度:
Container(
padding: EdgeInsets.all(8.w),
decoration: BoxDecoration(
color: item.color.withOpacity(0.1),
borderRadius: BorderRadius.circular(8.r),
),
child: Icon(item.icon, color: item.color, size: 20.sp),
),
背景色和图标色是同一个颜色,只是透明度不同。
这种设计让图标更突出,同时不会太刺眼。
圆角的选择:
8.r 的圆角比较柔和,和整体风格一致。
太大会显得圆滚滚,太小又没效果。
八、箭头图标的作用
trailing 放右箭头:
trailing: Icon(Icons.chevron_right, color: Colors.grey[400]),
右箭头暗示这是可点击的,会跳转到新页面。
灰色不抢视觉,但能起到引导作用。
这是 Material Design 的常见模式:
用户看到箭头就知道点击会有反应。
没有箭头的 ListTile 通常是纯展示或开关。
九、Consumer 的使用
为什么用 Consumer 而不是 Provider.of:
Consumer<CatProvider>(
builder: (context, provider, child) {
return Text('已记录 ${provider.cats.length} 只猫咪');
},
),
Consumer 只重建它包裹的部分,性能更好。
Provider.of 会导致整个 build 方法重新执行。
child 参数的作用:
如果有不依赖 provider 的子组件,可以放在 child 里。
这样数据变化时,child 不会重建。
十、渐变背景的实现
LinearGradient 的参数:
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.orange, Colors.orange.shade300],
),
begin 和 end 定义渐变方向,这里是从上到下。
colors 数组定义渐变的颜色,可以有多个。
为什么用 shade300:
shade300 比原色浅,形成自然的过渡。
如果两个颜色差太多,渐变会很突兀。
十一、间距的统一
页面中的间距:
SizedBox(height: 16.h),
// 或
padding: EdgeInsets.all(16.w),
统一用 16 作为基础间距单位。
需要更大间距时用 20 或 24,保持倍数关系。
为什么用 .h 和 .w:
这是 ScreenUtil 的扩展方法。
.h 是高度适配,.w 是宽度适配,不同屏幕等比缩放。
十二、页面底部留白
菜单区域最后:
SizedBox(height: 20.h),
底部留一些空白,滚动到底时不会太挤。
这是个小细节,但能提升用户体验。
小结
个人中心页面虽然功能简单,但涉及的知识点不少。渐变背景让头部更有层次,Consumer 实现数据实时更新,菜单分组让功能一目了然。代码上用私有类封装菜单项数据,用展开运算符简化列表渲染。这些都是实际开发中常用的技巧,掌握了能提高开发效率。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐



所有评论(0)