Flutter for OpenHarmony 视力保护提醒App实战 - 提醒历史记录查看
本文介绍了基于Flutter实现的提醒历史记录查看系统设计方案。系统包含三个核心功能模块:1)历史记录列表展示用户提醒数据;2)日期筛选功能支持按需查询;3)统计数据可视化模块通过卡片形式展示总提醒次数、总休息时间和完成天数等关键指标。设计方案采用分层架构,使用StatefulWidget管理状态,通过函数式编程方法处理数据聚合,并遵循Material Design规范实现UI组件。系统具有响应式

提醒历史记录查看是应用的重要功能,它可以帮助用户了解自己的提醒历史和眼睛保护情况。本文将详细讲解如何实现一个完整的提醒历史记录查看系统,包括历史记录列表、日期筛选、统计数据展示和数据分析等功能。
提醒历史页面的整体设计
提醒历史页面包含历史记录列表、统计数据展示和日期筛选等部分。这样的设计可以让用户全面查看和分析自己的提醒历史。
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class ReminderHistoryDetail extends StatefulWidget {
const ReminderHistoryDetail({super.key});
State<ReminderHistoryDetail> createState() => _ReminderHistoryDetailState();
}
class _ReminderHistoryDetailState extends State<ReminderHistoryDetail> {
late List<Map<String, dynamic>> history;
DateTime selectedDate = DateTime.now();
void initState() {
super.initState();
history = _generateHistoryData();
}
List<Map<String, dynamic>> _generateHistoryData() {
return [
{'date': '2024-01-15', 'reminders': 8, 'restTime': 40, 'completed': true},
{'date': '2024-01-14', 'reminders': 7, 'restTime': 35, 'completed': true},
{'date': '2024-01-13', 'reminders': 8, 'restTime': 40, 'completed': true},
{'date': '2024-01-12', 'reminders': 6, 'restTime': 30, 'completed': false},
{'date': '2024-01-11', 'reminders': 8, 'restTime': 40, 'completed': true},
{'date': '2024-01-10', 'reminders': 5, 'restTime': 25, 'completed': false},
];
}
这段代码定义了提醒历史页面的基本结构。导入了Flutter的Material库和屏幕适配库。ReminderHistoryDetail是一个有状态Widget,用于显示提醒历史记录。使用StatefulWidget可以管理页面的状态,包括历史记录列表和选中的日期。initState方法在组件初始化时调用,用于加载历史数据。_generateHistoryData方法生成示例数据,在实际应用中应该从数据库或API获取。每条历史记录包含日期、提醒次数、休息时间和完成状态。
历史记录使用有状态Widget来管理,这样可以支持动态更新和用户交互。
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('提醒历史'),
backgroundColor: const Color(0xFF2196F3),
foregroundColor: Colors.white,
),
body: SingleChildScrollView(
child: Column(
children: [
_buildStatisticsSection(),
SizedBox(height: 16.h),
_buildDateFilterSection(),
SizedBox(height: 16.h),
_buildHistoryListSection(),
],
),
),
);
}
build方法构建了整个页面的布局结构。使用Scaffold提供了Material Design的基本页面框架。AppBar显示页面标题和蓝色主题色。SingleChildScrollView包装了主体内容,确保当内容超过屏幕高度时可以滚动。通过将页面分解为三个主要部分(统计、筛选、列表),代码结构清晰,易于维护和扩展。SizedBox控制各组件之间的间距。
页面使用SingleChildScrollView确保内容可以滚动,这对于在小屏幕设备上显示所有内容很重要。
统计数据部分
统计数据展示区域显示用户的关键指标,包括总提醒次数、总休息时间和完成天数。
Widget _buildStatisticsSection() {
final totalReminders = history.fold<int>(0, (sum, item) => sum + (item['reminders'] as int));
final totalRestTime = history.fold<int>(0, (sum, item) => sum + (item['restTime'] as int));
final completedDays = history.where((item) => item['completed'] as bool).length;
return Container(
margin: EdgeInsets.all(16.w),
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'统计数据',
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.bold),
),
SizedBox(height: 16.h),
_buildStatisticsSection方法构建统计数据展示区域。首先使用fold方法计算总提醒次数和总休息时间,这是一个函数式编程的方法,可以对列表中的所有元素进行累加操作。使用where方法计算完成天数,通过过滤completed为true的记录。Container创建白色卡片容器,margin设置外边距,padding设置内边距。BoxDecoration定义卡片的样式,包括白色背景、圆角和阴影效果。Column作为主要布局容器,包含标题和统计卡片。
统计数据使用fold和where方法进行数据聚合,这是Dart中常用的函数式编程方法。
GridView.count(
crossAxisCount: 3,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisSpacing: 12.w,
mainAxisSpacing: 12.h,
children: [
_buildStatCard('总提醒次数', '$totalReminders', const Color(0xFF2196F3)),
_buildStatCard('总休息时间', '${totalRestTime}分', const Color(0xFF4CAF50)),
_buildStatCard('完成天数', '$completedDays天', const Color(0xFFFFC107)),
],
),
],
),
);
}
Widget _buildStatCard(String label, String value, Color color) {
return Container(
padding: EdgeInsets.all(12.w),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(8.r),
border: Border.all(color: color, width: 1),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
value,
style: TextStyle(
fontSize: 16.sp,
fontWeight: FontWeight.bold,
color: color,
),
),
SizedBox(height: 4.h),
Text(
label,
style: TextStyle(fontSize: 10.sp, color: Colors.grey),
textAlign: TextAlign.center,
),
],
),
);
}
GridView.count创建3列的统计卡片,shrinkWrap: true使网格自适应高度,physics: const NeverScrollableScrollPhysics()禁用网格滚动。_buildStatCard辅助方法构建单个统计卡片,包含数值、标签和颜色。Container创建卡片,color: color.withOpacity(0.1)创建半透明背景。Border.all添加彩色边框,width: 1使边框细致。Column竖直排列数值和标签,mainAxisAlignment: MainAxisAlignment.center使内容居中。
统计卡片使用不同的颜色区分不同的指标,提高了视觉区分度。
日期筛选部分
日期筛选器允许用户选择特定日期查看记录。这是一个重要的交互功能,可以帮助用户按时间段分析数据。
Widget _buildDateFilterSection() {
return Container(
margin: EdgeInsets.symmetric(horizontal: 16.w),
padding: EdgeInsets.all(12.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Row(
children: [
Icon(Icons.calendar_today, color: const Color(0xFF2196F3), size: 20.sp),
SizedBox(width: 12.w),
Expanded(
child: Text(
'${selectedDate.year}-${selectedDate.month.toString().padLeft(2, '0')}-${selectedDate.day.toString().padLeft(2, '0')}',
style: TextStyle(fontSize: 14.sp, fontWeight: FontWeight.w500),
),
),
ElevatedButton(
onPressed: () => _selectDate(context),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF2196F3),
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h),
),
child: Text('选择', style: TextStyle(fontSize: 12.sp)),
),
],
),
);
}
Future<void> _selectDate(BuildContext context) async {
final picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(2024, 1, 1),
lastDate: DateTime.now(),
);
if (picked != null && picked != selectedDate) {
setState(() => selectedDate = picked);
}
}
_buildDateFilterSection方法构建日期筛选器。Container创建白色卡片容器。Row用于水平排列日期图标、日期显示和选择按钮。Icon显示日期图标,color: const Color(0xFF2196F3)使用蓝色。日期格式化为YYYY-MM-DD格式,使用padLeft方法确保月份和日期始终是两位数。ElevatedButton创建选择按钮,onPressed回调调用_selectDate方法。_selectDate方法使用showDatePicker显示日期选择对话框,initialDate设置初始日期,firstDate和lastDate设置可选日期范围。选择后通过setState更新selectedDate变量。
日期筛选器提供了直观的日期选择方式,用户可以快速选择任意日期。
历史记录列表部分
历史记录列表显示按日期筛选后的所有提醒记录。每条记录显示日期、完成状态和统计数据。
Widget _buildHistoryListSection() {
final filteredHistory = history.where((item) {
return item['date'].toString().startsWith(
'${selectedDate.year}-${selectedDate.month.toString().padLeft(2, '0')}',
);
}).toList();
return Container(
margin: EdgeInsets.symmetric(horizontal: 16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'历史记录',
style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.bold),
),
SizedBox(height: 12.h),
if (filteredHistory.isEmpty)
Center(
child: Padding(
padding: EdgeInsets.symmetric(vertical: 32.h),
child: Text(
'暂无记录',
style: TextStyle(fontSize: 14.sp, color: Colors.grey),
),
),
)
else
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: filteredHistory.length,
itemBuilder: (context, index) {
return _buildHistoryCard(filteredHistory[index]);
},
),
],
),
);
}
_buildHistoryListSection方法构建历史记录列表。首先根据选中的日期筛选历史记录,使用where方法按月份过滤,只显示该月份的记录。如果没有记录,显示"暂无记录"提示。否则使用ListView.builder构建列表,shrinkWrap: true使列表自适应高度,physics: const NeverScrollableScrollPhysics()禁用列表滚动。itemCount指定列表项的数量,itemBuilder回调函数负责为每个索引构建对应的Widget。
列表筛选使用where方法按月份过滤历史记录,这种设计允许用户按月份查看历史数据。
Widget _buildHistoryCard(Map<String, dynamic> item) {
return Container(
margin: EdgeInsets.only(bottom: 12.h),
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12.r),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
item['date'],
style: TextStyle(fontSize: 14.sp, fontWeight: FontWeight.bold),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
decoration: BoxDecoration(
color: (item['completed'] as bool)
? const Color(0xFF4CAF50).withOpacity(0.1)
: const Color(0xFFF44336).withOpacity(0.1),
borderRadius: BorderRadius.circular(4.r),
),
child: Text(
(item['completed'] as bool) ? '已完成' : '未完成',
style: TextStyle(
fontSize: 12.sp,
color: (item['completed'] as bool)
? const Color(0xFF4CAF50)
: const Color(0xFFF44336),
fontWeight: FontWeight.w500,
),
),
),
],
),
SizedBox(height: 12.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_buildStatItem('提醒次数', '${item['reminders']}次', const Color(0xFF2196F3)),
_buildStatItem('休息时间', '${item['restTime']}分', const Color(0xFF4CAF50)),
],
),
],
),
);
}
_buildHistoryCard方法构建单个历史记录卡片。Container创建白色卡片容器,margin设置卡片之间的间距,padding设置卡片内部的内容间距。Column作为主要布局容器,包含日期行和统计数据行。第一个Row显示日期和完成状态,mainAxisAlignment: MainAxisAlignment.spaceBetween使日期和状态标签分别显示在行的两端。完成状态使用不同的颜色表示:绿色表示已完成,红色表示未完成。第二个Row显示统计数据,mainAxisAlignment: MainAxisAlignment.spaceAround均匀分布两个统计项。_buildStatItem辅助方法构建统计项,显示提醒次数和休息时间。
历史记录卡片使用白色卡片容器展示,提供了良好的视觉隔离。完成状态标签使用颜色编码,用户可以快速识别。
总结
通过以上的设计,我们实现了一个完整的提醒历史记录查看系统。用户可以查看自己的提醒历史、统计数据、按日期筛选记录。这样的设计使得用户可以更好地了解自己的眼睛保护情况,并根据历史数据制定更有效的护眼计划。
在实际应用中,我们可以进一步扩展这个系统,添加更多的筛选选项、数据导出、图表展示等功能。例如,可以添加日期范围筛选、按提醒次数排序、导出为CSV等功能,使用户能够更灵活地查看和分析历史数据。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐


所有评论(0)