在这里插入图片描述

前言

水分摄入追踪是运动健康应用中帮助用户保持良好水合状态的重要功能。运动过程中和日常生活中保持充足的水分摄入对健康至关重要。本文将详细介绍如何在Flutter与OpenHarmony平台上实现水分摄入追踪组件,包括饮水记录、目标设定、提醒功能等模块的完整实现方案。

Flutter水分数据模型

class WaterIntake {
  final String id;
  final int amount;
  final DateTime timestamp;
  final String type;
  
  WaterIntake({required this.id, required this.amount, required this.timestamp, this.type = 'water'});
}

class DailyWaterData {
  final DateTime date;
  final int totalIntake;
  final int targetIntake;
  final List<WaterIntake> records;
  
  DailyWaterData({
    required this.date,
    required this.totalIntake,
    required this.targetIntake,
    required this.records,
  });
  
  double get progress => (totalIntake / targetIntake * 100).clamp(0, 100);
  bool get isGoalReached => totalIntake >= targetIntake;
  int get remaining => (targetIntake - totalIntake).clamp(0, targetIntake);
  
  String get statusText {
    if (progress >= 100) return '已达标 💧';
    if (progress >= 75) return '即将达标';
    if (progress >= 50) return '继续加油';
    return '需要多喝水';
  }
}

水分数据模型定义了饮水记录和每日汇总数据。WaterIntake记录单次饮水的量、时间和类型(水、茶、咖啡等)。DailyWaterData汇总每日数据,包含总摄入量、目标量和记录列表。progress计算完成百分比,remaining计算还需摄入的量。statusText根据进度返回鼓励性文字。

OpenHarmony水分存储服务

import dataPreferences from '@ohos.data.preferences';

class WaterStorageService {
  private preferences: dataPreferences.Preferences | null = null;
  
  async initialize(context: Context): Promise<void> {
    this.preferences = await dataPreferences.getPreferences(context, 'water_intake');
  }
  
  async addIntake(amount: number): Promise<void> {
    if (!this.preferences) return;
    
    let today = new Date().toISOString().split('T')[0];
    let recordsJson = await this.preferences.get(today, '[]') as string;
    let records: Array<object> = JSON.parse(recordsJson);
    
    records.push({
      id: Date.now().toString(),
      amount: amount,
      timestamp: Date.now(),
    });
    
    await this.preferences.put(today, JSON.stringify(records));
    await this.preferences.flush();
  }
  
  async getTodayIntake(): Promise<number> {
    if (!this.preferences) return 0;
    
    let today = new Date().toISOString().split('T')[0];
    let recordsJson = await this.preferences.get(today, '[]') as string;
    let records: Array<object> = JSON.parse(recordsJson);
    
    return records.reduce((sum: number, r: object) => sum + (r['amount'] as number), 0);
  }
  
  async getTargetIntake(): Promise<number> {
    if (!this.preferences) return 2000;
    return await this.preferences.get('target', 2000) as number;
  }
  
  async setTargetIntake(target: number): Promise<void> {
    if (this.preferences) {
      await this.preferences.put('target', target);
      await this.preferences.flush();
    }
  }
}

水分存储服务按日期存储饮水记录。addIntake方法添加新的饮水记录,getTodayIntake方法计算今日总摄入量。使用日期字符串作为键,每天的记录存储为JSON数组。目标摄入量单独存储,默认2000毫升。这种设计支持按天查询和统计。

Flutter水分显示组件

class WaterIntakeDisplay extends StatelessWidget {
  final DailyWaterData data;
  final VoidCallback onAddWater;
  
  const WaterIntakeDisplay({Key? key, required this.data, required this.onAddWater}) : super(key: key);
  
  
  Widget build(BuildContext context) {
    return Card(
      margin: EdgeInsets.all(16),
      child: Padding(
        padding: EdgeInsets.all(20),
        child: Column(
          children: [
            Stack(
              alignment: Alignment.center,
              children: [
                SizedBox(
                  width: 150,
                  height: 150,
                  child: CircularProgressIndicator(
                    value: data.progress / 100,
                    strokeWidth: 12,
                    backgroundColor: Colors.blue.withOpacity(0.2),
                    valueColor: AlwaysStoppedAnimation(Colors.blue),
                  ),
                ),
                Column(
                  children: [
                    Text('💧', style: TextStyle(fontSize: 32)),
                    Text('${data.totalIntake}', style: TextStyle(fontSize: 32, fontWeight: FontWeight.bold)),
                    Text('/ ${data.targetIntake} ml', style: TextStyle(color: Colors.grey)),
                  ],
                ),
              ],
            ),
            SizedBox(height: 16),
            Text(data.statusText, style: TextStyle(fontSize: 16, color: data.isGoalReached ? Colors.green : Colors.blue)),
            SizedBox(height: 16),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                _buildQuickAddButton(100, onAddWater),
                _buildQuickAddButton(200, onAddWater),
                _buildQuickAddButton(300, onAddWater),
                _buildQuickAddButton(500, onAddWater),
              ],
            ),
          ],
        ),
      ),
    );
  }
  
  Widget _buildQuickAddButton(int amount, VoidCallback onTap) {
    return OutlinedButton(
      onPressed: onTap,
      child: Text('+${amount}ml'),
    );
  }
}

水分显示组件以圆形进度环展示今日饮水进度。中央显示水滴emoji、当前摄入量和目标量。底部提供快速添加按钮,常用量100ml、200ml、300ml、500ml一键添加。状态文字根据进度变化,达标后显示绿色。这种设计让用户快速了解饮水情况并便捷记录。

OpenHarmony饮水提醒服务

import reminderAgentManager from '@ohos.reminderAgentManager';

class WaterReminderService {
  async setHourlyReminder(startHour: number, endHour: number): Promise<Array<number>> {
    let reminderIds: Array<number> = [];
    
    for (let hour = startHour; hour <= endHour; hour += 2) {
      let reminderRequest: reminderAgentManager.ReminderRequestAlarm = {
        reminderType: reminderAgentManager.ReminderType.REMINDER_TYPE_ALARM,
        hour: hour,
        minute: 0,
        daysOfWeek: [1, 2, 3, 4, 5, 6, 7],
        title: '💧 喝水提醒',
        content: '该喝水了,保持水分充足!',
        ringDuration: 5,
        snoozeTimes: 0,
      };
      
      let id = await reminderAgentManager.publishReminder(reminderRequest);
      reminderIds.push(id);
    }
    
    return reminderIds;
  }
  
  async cancelAllReminders(reminderIds: Array<number>): Promise<void> {
    for (let id of reminderIds) {
      await reminderAgentManager.cancelReminder(id);
    }
  }
}

饮水提醒服务设置定时提醒用户喝水。setHourlyReminder方法在指定时间范围内每2小时设置一个提醒,帮助用户养成规律饮水习惯。提醒内容简洁友好,使用水滴emoji增加亲和力。用户可以自定义提醒的开始和结束时间,避免夜间打扰。

Flutter饮水历史图表

class WaterHistoryChart extends StatelessWidget {
  final List<int> weeklyData;
  final int target;
  
  const WaterHistoryChart({Key? key, required this.weeklyData, required this.target}) : super(key: key);
  
  
  Widget build(BuildContext context) {
    List<String> days = ['一', '二', '三', '四', '五', '六', '日'];
    
    return Container(
      height: 200,
      padding: EdgeInsets.all(16),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.end,
        children: List.generate(7, (index) {
          double percentage = weeklyData[index] / target;
          double height = (percentage.clamp(0, 1.2)) * 120;
          bool reachedGoal = weeklyData[index] >= target;
          
          return Expanded(
            child: Padding(
              padding: EdgeInsets.symmetric(horizontal: 4),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.end,
                children: [
                  Text('${(weeklyData[index] / 1000).toStringAsFixed(1)}L', style: TextStyle(fontSize: 10)),
                  SizedBox(height: 4),
                  Container(
                    height: height,
                    decoration: BoxDecoration(
                      color: reachedGoal ? Colors.blue : Colors.blue.withOpacity(0.5),
                      borderRadius: BorderRadius.circular(4),
                    ),
                  ),
                  SizedBox(height: 4),
                  Text(days[index], style: TextStyle(fontSize: 12)),
                ],
              ),
            ),
          );
        }),
      ),
    );
  }
}

饮水历史图表以柱状图展示一周的饮水情况。每根柱子高度按摄入量与目标的比例计算,达标的日期使用深蓝色,未达标使用浅蓝色。顶部显示具体升数,底部显示星期几。这种图表帮助用户回顾饮水习惯,发现需要改进的日期。

Flutter饮水设置组件

class WaterSettingsWidget extends StatefulWidget {
  final int currentTarget;
  final Function(int) onTargetChanged;
  
  const WaterSettingsWidget({Key? key, required this.currentTarget, required this.onTargetChanged}) : super(key: key);
  
  
  State<WaterSettingsWidget> createState() => _WaterSettingsWidgetState();
}

class _WaterSettingsWidgetState extends State<WaterSettingsWidget> {
  late int _target;
  
  
  void initState() {
    super.initState();
    _target = widget.currentTarget;
  }
  
  
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text('每日目标', style: TextStyle(fontWeight: FontWeight.bold)),
        SizedBox(height: 8),
        Text('$_target ml', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.blue)),
        Slider(
          value: _target.toDouble(),
          min: 1000,
          max: 4000,
          divisions: 30,
          onChanged: (value) {
            setState(() => _target = value.toInt());
            widget.onTargetChanged(_target);
          },
        ),
        SizedBox(height: 8),
        Text('建议: 成人每日饮水量约2000-2500ml', style: TextStyle(color: Colors.grey, fontSize: 12)),
      ],
    );
  }
}

饮水设置组件让用户自定义每日饮水目标。Slider范围1000-4000ml,覆盖不同人群的需求。底部提供健康建议作为参考。目标变化通过回调通知父组件保存。这种设置让用户可以根据自己的身体状况和运动量调整目标。

总结

本文全面介绍了Flutter与OpenHarmony平台上水分摄入追踪组件的实现方案。从数据模型到存储服务,从进度展示到定时提醒,涵盖了饮水追踪功能的各个方面。通过便捷的记录方式和及时的提醒,我们可以帮助用户养成良好的饮水习惯,保持身体水合状态。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐