Flutter for OpenHarmony 猫咪管家App实战 - 驱虫记录实现
本文介绍了如何实现一个猫咪驱虫记录管理功能。主要包含以下要点: 页面结构:采用Scaffold框架,包含顶部导航栏、内容区和悬浮添加按钮 状态管理:使用Provider监听数据变化,自动刷新UI 内容展示:分为驱虫知识科普卡片和历史记录列表两部分 空状态处理:显示引导图标和添加按钮 记录卡片:包含驱虫类型、日期和下次提醒时间 日期格式化:使用intl包处理日期显示 功能特点: 直观展示驱虫科普知识

定期驱虫是养猫的必修课。体内驱虫、体外驱虫,时间间隔各不相同,很容易忘记。今天我们来实现一个驱虫记录功能,帮助铲屎官们管理猫咪的驱虫计划。
需求分析
驱虫记录页面需要实现以下功能:
- 展示驱虫相关的科普知识
- 列表显示历史驱虫记录
- 支持快速添加新记录
- 显示下次驱虫提醒时间
想清楚需求再动手,能避免很多返工。
依赖引入
先把需要的包引入进来:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:intl/intl.dart';
import '../../providers/health_provider.dart';
import '../../models/health_record.dart';
import 'add_health_record_screen.dart';
Material是Flutter的UI基础库,Provider处理状态管理。
screenutil做屏幕适配,intl负责日期的格式化显示。
页面类定义
驱虫记录页面是一个无状态组件:
class DewormingScreen extends StatelessWidget {
final String catId;
const DewormingScreen({super.key, required this.catId});
通过catId参数确定是哪只猫咪的驱虫记录。
StatelessWidget配合Provider使用,数据变化时自动刷新。
主体结构搭建
build方法构建整个页面:
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('驱虫记录')),
body: Consumer<HealthProvider>(
builder: (context, provider, child) {
final records = provider.getRecordsByType(catId, HealthRecordType.deworming);
Scaffold是页面的骨架,包含顶部导航栏和主体内容。
Consumer监听HealthProvider,数据变化时builder会重新执行。
空状态处理
没有记录时显示引导界面:
if (records.isEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.bug_report, size: 80.sp, color: Colors.grey[300]),
SizedBox(height: 16.h),
Text('暂无驱虫记录', style: TextStyle(color: Colors.grey[600])),
用虫子图标暗示驱虫主题,灰色调表示空状态。
Center和Column组合实现垂直居中布局。
添加引导按钮:
SizedBox(height: 16.h),
ElevatedButton(
onPressed: () => _addRecord(context),
child: const Text('添加驱虫记录'),
),
],
),
);
}
空状态下提供明确的操作入口。
用户点击按钮就能直接跳转到添加页面。
列表内容展示
有数据时展示完整列表:
return ListView(
padding: EdgeInsets.all(16.w),
children: [
_buildDewormingInfo(),
SizedBox(height: 16.h),
Text('驱虫记录', style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.bold)),
SizedBox(height: 8.h),
...records.map((r) => _buildRecordCard(r)),
],
);
},
),
ListView支持滚动,适合展示不定长度的内容。
先放知识卡片,再放记录列表,层次分明。
悬浮添加按钮:
floatingActionButton: FloatingActionButton(
onPressed: () => _addRecord(context),
backgroundColor: Colors.orange,
child: const Icon(Icons.add),
),
);
}
FAB是Material Design的标准添加按钮。
固定在右下角,随时可以点击添加新记录。
驱虫知识卡片
科普内容帮助用户了解驱虫知识:
Widget _buildDewormingInfo() {
return Card(
color: Colors.green[50],
child: Padding(
padding: EdgeInsets.all(16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.info, color: Colors.green, size: 20.sp),
SizedBox(width: 8.w),
Text('驱虫知识', style: TextStyle(fontWeight: FontWeight.bold, color: Colors.green[800])),
],
),
绿色主题与驱虫话题相关联,给人健康的感觉。
Row布局让图标和标题水平排列。
知识内容详情:
SizedBox(height: 8.h),
Text(
'• 体内驱虫:每3个月一次\n'
'• 体外驱虫:每月一次(夏季)\n'
'• 常见体内寄生虫:蛔虫、绦虫、钩虫\n'
'• 常见体外寄生虫:跳蚤、蜱虫、耳螨',
style: TextStyle(fontSize: 13.sp, color: Colors.green[700]),
),
],
),
),
);
}
用项目符号列出关键信息,方便快速浏览。
体内体外驱虫的频率不同,这是很多新手容易忽略的。
记录卡片设计
每条驱虫记录用卡片展示:
Widget _buildRecordCard(HealthRecord record) {
return Card(
margin: EdgeInsets.only(bottom: 8.h),
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.green[100],
child: Icon(Icons.bug_report, color: Colors.green, size: 20.sp),
),
title: Text(record.title),
Card提供阴影和圆角效果,视觉上更有层次。
CircleAvatar作为左侧图标,统一的绿色主题。
日期信息显示:
subtitle: Text(DateFormat('yyyy-MM-dd').format(record.date)),
副标题显示驱虫日期,格式清晰易读。
DateFormat来自intl包,支持各种日期格式。
下次驱虫提醒:
trailing: record.nextDate != null
? Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text('下次', style: TextStyle(fontSize: 10.sp, color: Colors.grey)),
Text(DateFormat('MM-dd').format(record.nextDate!), style: TextStyle(color: Colors.orange)),
],
)
: null,
),
);
}
下次驱虫日期用橙色突出显示,起到提醒作用。
条件渲染,没有设置下次日期时不显示trailing。
添加记录导航
跳转到添加页面的方法:
void _addRecord(BuildContext context) {
Navigator.push(context, MaterialPageRoute(
builder: (_) => AddHealthRecordScreen(catId: catId, initialType: HealthRecordType.deworming),
));
}
}
Navigator.push实现页面跳转。
initialType设为deworming,添加页面会默认选中驱虫类型。
数据筛选逻辑
Provider中的筛选方法:
List<HealthRecord> getRecordsByType(String catId, HealthRecordType type) {
return _records
.where((r) => r.catId == catId && r.type == type)
.toList()
..sort((a, b) => b.date.compareTo(a.date));
}
where方法筛选出符合条件的记录。
级联操作符…让排序和转换一气呵成。
颜色方案设计
驱虫页面使用绿色系:
Colors.green[50] // 卡片背景色
Colors.green[100] // 头像背景色
Colors.green[700] // 正文颜色
Colors.green[800] // 标题颜色
绿色给人健康、自然的感觉,与驱虫主题契合。
不同深浅的绿色形成视觉层次。
强调色使用橙色:
Colors.orange // 下次日期、FAB按钮
橙色作为App的主题色,用于强调重要信息。
与绿色形成对比,更容易吸引注意力。
布局技巧总结
Column实现垂直布局:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(...),
SizedBox(height: 8.h),
Text(...),
],
)
crossAxisAlignment设为start让内容左对齐。
SizedBox作为间距组件,比Padding更灵活。
Row实现水平布局:
Row(
children: [
Icon(Icons.info, color: Colors.green, size: 20.sp),
SizedBox(width: 8.w),
Text('驱虫知识', ...),
],
)
Row中的子组件水平排列。
SizedBox控制组件之间的间距。
ListTile详解
ListTile是列表项的标准组件:
ListTile(
leading: CircleAvatar(...), // 左侧图标
title: Text(record.title), // 主标题
subtitle: Text(...), // 副标题
trailing: Column(...), // 右侧内容
)
四个位置可以放置不同内容,布局自动处理。
比手动用Row和Column布局省事很多。
条件渲染写法
三元表达式处理可选内容:
trailing: record.nextDate != null
? Column(...)
: null,
当nextDate存在时显示Column,否则为null。
null的trailing不会占用空间。
字符串拼接中的条件:
'${record.hospital != null ? ' · ${record.hospital}' : ''}'
如果hospital不为null,就拼接上去。
这种写法在显示可选信息时很常用。
日期格式化
完整日期格式:
DateFormat('yyyy-MM-dd').format(record.date)
输出类似"2024-03-15"的格式。
yyyy是四位年份,MM是两位月份,dd是两位日期。
简短日期格式:
DateFormat('MM-dd').format(record.nextDate!)
只显示月日,适合空间有限的场景。
感叹号表示已确认nextDate不为null。
屏幕适配实践
使用screenutil的适配单位:
Icon(Icons.bug_report, size: 80.sp, color: Colors.grey[300])
SizedBox(height: 16.h)
EdgeInsets.all(16.w)
TextStyle(fontSize: 13.sp, color: Colors.green[700])
.sp用于字体和图标,根据屏幕宽度缩放。
.h用于高度,.w用于宽度,保证不同设备上的一致性。
Consumer使用要点
Consumer监听Provider变化:
Consumer<HealthProvider>(
builder: (context, provider, child) {
final records = provider.getRecordsByType(...);
// 使用records构建UI
},
)
builder函数在Provider数据变化时重新执行。
provider参数可以直接调用Provider的方法。
空状态设计原则
好的空状态应该包含:
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(...), // 主题相关的图标
SizedBox(...),
Text('暂无驱虫记录'), // 说明文字
SizedBox(...),
ElevatedButton(...), // 操作引导
],
),
)
图标让页面不会太空,文字说明当前状态。
按钮引导用户进行下一步操作。
小结
驱虫记录页面的实现涵盖了这些知识点:
- Provider和Consumer的配合使用
- 空状态和列表状态的切换
- Card和ListTile的组合
- 条件渲染和日期格式化
这些都是Flutter开发中的常用技巧,掌握了就能应对大部分列表页面的开发。
欢迎加入OpenHarmony跨平台开发社区,一起交流Flutter开发经验:
https://openharmonycrossplatform.csdn.net
更多推荐
所有评论(0)