在这里插入图片描述

提醒历史记录查看是应用的重要功能,它可以帮助用户了解自己的提醒历史和眼睛保护情况。本文将详细讲解如何实现一个完整的提醒历史记录查看系统,包括历史记录列表、日期筛选、统计数据展示和数据分析等功能。

提醒历史页面的整体设计

提醒历史页面包含历史记录列表、统计数据展示和日期筛选等部分。这样的设计可以让用户全面查看和分析自己的提醒历史。

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

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐