鸿蒙flutter第三方库适配 - 运动步数追踪器
运行效果图运动步数追踪器是一款专注于健康管理的运动记录应用,旨在帮助用户养成每日运动的好习惯。应用通过智能算法记录用户每日步数,精确计算消耗卡路里,实时展示运动轨迹,并提供个性化的目标设定和成就激励系统。应用以活力绿色为主色调,象征健康与生机。涵盖运动主页、实时追踪、历史记录、成就系统四大核心模块。用户可以设定个人运动目标,追踪每日运动数据,查看历史运动记录,解锁各类成就徽章,在运动中收获健康与快
运动步数追踪器应用
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
适配的第三方库地址:
- location: https://pub.dev/packages/location
- shared_preferences: https://pub.dev/packages/shared_preferences
- flutter_local_notifications: https://pub.dev/packages/flutter_local_notifications
- wakelock: https://pub.dev/packages/wakelock
一、项目概述
运行效果图





1.1 应用简介
运动步数追踪器是一款专注于健康管理的运动记录应用,旨在帮助用户养成每日运动的好习惯。应用通过智能算法记录用户每日步数,精确计算消耗卡路里,实时展示运动轨迹,并提供个性化的目标设定和成就激励系统。
应用以活力绿色为主色调,象征健康与生机。涵盖运动主页、实时追踪、历史记录、成就系统四大核心模块。用户可以设定个人运动目标,追踪每日运动数据,查看历史运动记录,解锁各类成就徽章,在运动中收获健康与快乐。
1.2 核心功能
| 功能模块 | 功能描述 | 实现方式 |
|---|---|---|
| 步数记录 | 实时记录用户行走步数 | 传感器/模拟数据 |
| 卡路里计算 | 根据步数计算消耗热量 | 算法计算 |
| 轨迹追踪 | 展示用户运动路线 | GPS定位 |
| 目标设定 | 自定义每日运动目标 | 本地存储 |
| 成就系统 | 解锁运动成就徽章 | 成就引擎 |
| 历史记录 | 查看过往运动数据 | 数据持久化 |
| 数据统计 | 周/月运动数据汇总 | 图表展示 |
| 提醒通知 | 运动目标提醒推送 | 本地通知 |
1.3 运动类型定义
| 序号 | 运动类型 | Emoji | 描述 | 卡路里消耗/步 |
|---|---|---|---|---|
| 1 | 步行 | 🚶 | 日常步行运动 | 0.04 千卡 |
| 2 | 慢跑 | 🏃 | 中等强度跑步 | 0.08 千卡 |
| 3 | 快走 | 🚀 | 高速步行 | 0.06 千卡 |
| 4 | 徒步 | 🥾 | 户外登山徒步 | 0.07 千卡 |
1.4 目标等级定义
| 序号 | 目标名称 | Emoji | 步数目标 | 卡路里目标 | 距离目标 |
|---|---|---|---|---|---|
| 1 | 入门级 | 🌱 | 3,000步 | 120千卡 | 2公里 |
| 2 | 标准级 | 🌿 | 6,000步 | 240千卡 | 4公里 |
| 3 | 进阶级 | 🌳 | 10,000步 | 400千卡 | 7公里 |
| 4 | 挑战级 | 🏔️ | 15,000步 | 600千卡 | 10公里 |
| 5 | 专家级 | 🏆 | 20,000步 | 800千卡 | 14公里 |
1.5 成就类型定义
| 序号 | 成就名称 | Emoji | 描述 | 积分 |
|---|---|---|---|---|
| 1 | 初出茅庐 | 🏃 | 完成第一次运动记录 | 10 |
| 2 | 目标达成 | 🎯 | 单日步数达到目标 | 50 |
| 3 | 坚持不懈 | 🔥 | 连续7天完成目标 | 100 |
| 4 | 马拉松达人 | 🏅 | 累计步行42.195公里 | 200 |
| 5 | 燃脂先锋 | 💪 | 单日消耗500卡路里 | 150 |
| 6 | 早起鸟儿 | 🌅 | 早上6点前开始运动 | 30 |
| 7 | 夜猫子 | 🌙 | 晚上10点后仍在运动 | 30 |
| 8 | 速度之星 | ⚡ | 1小时内步行5公里 | 80 |
1.6 数据统计周期
| 序号 | 统计周期 | Emoji | 数据范围 | 展示形式 |
|---|---|---|---|---|
| 1 | 今日 | 📅 | 当日数据 | 实时更新 |
| 2 | 本周 | 📊 | 近7天数据 | 柱状图 |
| 3 | 本月 | 📈 | 近30天数据 | 折线图 |
| 4 | 全部 | 🏆 | 累计数据 | 汇总卡片 |
1.7 技术栈
| 技术领域 | 技术选型 | 版本要求 |
|---|---|---|
| 开发框架 | Flutter | >= 3.0.0 |
| 编程语言 | Dart | >= 2.17.0 |
| 设计规范 | Material Design 3 | - |
| 状态管理 | StatefulWidget | - |
| 数据存储 | SharedPreferences | >= 2.0.0 |
| 定位服务 | Location | >= 4.0.0 |
| 本地通知 | FlutterLocalNotifications | >= 15.0.0 |
| 屏幕唤醒 | Wakelock | >= 0.6.0 |
| 目标平台 | 鸿蒙OS / Web | API 21+ |
1.8 项目结构
lib/
└── main_fitness_tracker.dart
├── FitnessTrackerApp # 应用入口
├── AchievementType # 成就类型枚举
├── DailyGoal # 每日目标模型
├── WorkoutRecord # 运动记录模型
├── Achievement # 成就模型
├── UserStats # 用户统计模型
├── FitnessTrackerHomePage # 主页面(底部导航)
├── _buildHomePage # 主页
├── _buildTrackingPage # 运动追踪页
├── _buildHistoryPage # 历史记录页
├── _buildAchievementsPage # 成就页
├── WeeklyChartPainter # 周统计图表绘制器
└── RoutePainter # 轨迹绘制器
二、系统架构
2.1 整体架构图
2.2 类图设计
2.3 页面导航流程
2.4 运动追踪流程
三、核心模块设计
3.1 数据模型设计
3.1.1 成就类型枚举 (AchievementType)
enum AchievementType {
firstStep('初出茅庐', '🏃', '完成第一次运动记录', 10),
dailyGoal('目标达成', '🎯', '单日步数达到目标', 50),
weeklyStreak('坚持不懈', '🔥', '连续7天完成目标', 100),
marathonRunner('马拉松达人', '🏅', '累计步行42.195公里', 200),
calorieBurner('燃脂先锋', '💪', '单日消耗500卡路里', 150),
earlyBird('早起鸟儿', '🌅', '早上6点前开始运动', 30),
nightOwl('夜猫子', '🌙', '晚上10点后仍在运动', 30),
speedster('速度之星', '⚡', '1小时内步行5公里', 80);
final String label;
final String emoji;
final String description;
final int points;
const AchievementType(this.label, this.emoji, this.description, this.points);
}
3.1.2 每日目标模型 (DailyGoal)
class DailyGoal {
final int stepTarget;
final double calorieTarget;
final double distanceTarget;
final DateTime createdAt;
const DailyGoal({
required this.stepTarget,
required this.calorieTarget,
required this.distanceTarget,
required this.createdAt,
});
DailyGoal copyWith({
int? stepTarget,
double? calorieTarget,
double? distanceTarget,
}) {
return DailyGoal(
stepTarget: stepTarget ?? this.stepTarget,
calorieTarget: calorieTarget ?? this.calorieTarget,
distanceTarget: distanceTarget ?? this.distanceTarget,
createdAt: createdAt,
);
}
}
3.1.3 运动记录模型 (WorkoutRecord)
class WorkoutRecord {
final String id;
final DateTime startTime;
final DateTime endTime;
final int steps;
final double distance;
final double calories;
final List<Offset> route;
final double avgSpeed;
const WorkoutRecord({
required this.id,
required this.startTime,
required this.endTime,
required this.steps,
required this.distance,
required this.calories,
required this.route,
required this.avgSpeed,
});
}
3.1.4 成就分布统计
3.2 页面结构设计
3.2.1 主页面布局
3.2.2 主页结构
3.2.3 运动追踪页结构
3.2.4 历史记录页结构
3.3 运动引擎逻辑
3.4 成就检测逻辑
四、UI设计规范
4.1 配色方案
应用以活力绿色为主色调,象征健康与生机:
| 颜色类型 | 色值 | 用途 |
|---|---|---|
| 主色 | #4CAF50 (Green) | 导航、主题元素 |
| 辅助色 | #81C784 | 卡片背景 |
| 第三色 | #A5D6A7 | 进度条背景 |
| 强调色 | #C8E6C9 | 成就页面 |
| 背景色 | #FAFAFA | 页面背景 |
| 卡片背景 | #FFFFFF | 信息卡片 |
| 步数色 | #4CAF50 | 步数统计 |
| 卡路里色 | #FF9800 | 卡路里统计 |
| 距离色 | #2196F3 | 距离统计 |
4.2 目标等级配色
| 等级 | 色值 | 视觉效果 |
|---|---|---|
| 入门级 | #4CAF50 | 绿色 |
| 标准级 | #8BC34A | 浅绿 |
| 进阶级 | #CDDC39 | 黄绿 |
| 挑战级 | #FFC107 | 黄色 |
| 专家级 | #FF9800 | 橙色 |
4.3 字体规范
| 元素 | 字号 | 字重 | 颜色 |
|---|---|---|---|
| 页面标题 | 24px | Bold | 主色 |
| 步数显示 | 36px | Bold | #FFFFFF |
| 统计数值 | 20px | Bold | #000000 |
| 卡片标题 | 18px | Bold | #000000 |
| 提示文字 | 14px | Regular | #666666 |
| 标签文字 | 12px | Regular | #999999 |
4.4 组件规范
4.4.1 目标进度卡片
┌─────────────────────────────────────┐
│ 今日目标进度 [设置] │
│ │
│ 🚶 步数 8,500 / 10,000 步 │
│ ═════════════●═══════════════ │
│ 85% │
│ │
│ 🔥 卡路里 340 / 400 千卡 │
│ ════════════════●═══════════ │
│ 85% │
│ │
│ 🗺️ 距离 5.8 / 7.0 公里 │
│ ═══════════════●════════════ │
│ 83% │
└─────────────────────────────────────┘
4.4.2 今日统计卡片
┌─────────────────────────────────────┐
│ 今日运动数据 │
│ │
│ 🚶 🔥 🗺️ │
│ 8,500 340 5.8 │
│ 步 千卡 公里 │
└─────────────────────────────────────┘
4.4.3 运动追踪界面
┌─────────────────────────────────────┐
│ 🚶 8,500步 🗺️ 5.8km 🔥 340千卡 │
│ │
│ [轨迹地图区域] │
│ ╔═══════════════════════════╗ │
│ ║ 🔵 ────────●──────── 🔴 ║ │
│ ║ ║ │
│ ╚═══════════════════════════╝ │
│ │
│ ⏱️ 运动时长: 45 分钟 │
│ │
│ ┌─────────────────────────────┐ │
│ │ ▶️ 开始运动 │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
4.4.4 历史记录卡片
┌─────────────────────────────────────┐
│ 🚶 4月12日 45分钟 │
│ 07:30 │
│ ───────────────────────────────── │
│ 6,500步 4.5公里 260千卡 │
└─────────────────────────────────────┘
4.4.5 成就卡片
┌─────────────────────────────────────┐
│ 成就列表 │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ 🏃 │ │ 🎯 │ │
│ │ 初出茅庐 │ │ 目标达成 │ │
│ │ 完成第一次 │ │ 单日步数达 │ │
│ │ 运动记录 │ │ 到目标 │ │
│ │ ✅ 已解锁 │ │ ✅ 已解锁 │ │
│ │ 10 积分 │ │ 50 积分 │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────┘
五、核心功能实现
5.1 运动引擎实现
class FitnessEngine {
WorkoutRecord createWorkoutRecord(
DateTime startTime,
DateTime endTime,
int steps,
List<Offset> route,
) {
final distance = _calculateDistance(route);
final calories = _calculateCalories(steps);
final avgSpeed = _calculateAvgSpeed(distance, startTime, endTime);
return WorkoutRecord(
id: 'workout_${DateTime.now().millisecondsSinceEpoch}',
startTime: startTime,
endTime: endTime,
steps: steps,
distance: distance,
calories: calories,
route: route,
avgSpeed: avgSpeed,
);
}
double _calculateDistance(List<Offset> route) {
double distance = 0;
for (int i = 1; i < route.length; i++) {
distance += _calculatePointDistance(route[i - 1], route[i]);
}
return distance;
}
double _calculateCalories(int steps) {
return steps * 0.04;
}
double _calculateAvgSpeed(double distance, DateTime start, DateTime end) {
final hours = end.difference(start).inMinutes / 60;
return hours > 0 ? distance / hours : 0;
}
double _calculatePointDistance(Offset a, Offset b) {
return sqrt(pow(a.dx - b.dx, 2) + pow(a.dy - b.dy, 2));
}
}
5.2 定位管理器实现
class LocationManager {
StreamSubscription<LocationData>? _locationSubscription;
final List<Offset> _route = [];
Future<void> startTracking(Function(Offset) onLocationUpdate) async {
bool serviceEnabled = await location.serviceEnabled();
if (!serviceEnabled) {
serviceEnabled = await location.requestService();
if (!serviceEnabled) return;
}
PermissionStatus permission = await location.hasPermission();
if (permission == PermissionStatus.denied) {
permission = await location.requestPermission();
if (permission != PermissionStatus.granted) return;
}
_locationSubscription = location.onLocationChanged.listen((data) {
final point = Offset(data.latitude ?? 0, data.longitude ?? 0);
_route.add(point);
onLocationUpdate(point);
});
}
Future<void> stopTracking() async {
await _locationSubscription?.cancel();
_locationSubscription = null;
}
List<Offset> getRoute() => List.unmodifiable(_route);
}
5.3 成就系统实现
class AchievementSystem {
List<Achievement> checkAchievements(
WorkoutRecord record,
UserStats stats,
List<Achievement> currentAchievements,
) {
final newAchievements = <Achievement>[];
for (var achievement in currentAchievements) {
if (!achievement.isUnlocked && _checkCondition(achievement.type, record, stats)) {
newAchievements.add(achievement.copyWith(
isUnlocked: true,
unlockedAt: DateTime.now(),
));
}
}
return newAchievements;
}
bool _checkCondition(AchievementType type, WorkoutRecord record, UserStats stats) {
switch (type) {
case AchievementType.firstStep:
return stats.totalWorkouts == 1;
case AchievementType.dailyGoal:
return record.steps >= 10000;
case AchievementType.weeklyStreak:
return stats.currentStreak >= 7;
case AchievementType.marathonRunner:
return stats.totalDistance >= 42.195;
case AchievementType.calorieBurner:
return record.calories >= 500;
case AchievementType.earlyBird:
return record.startTime.hour < 6;
case AchievementType.nightOwl:
return record.startTime.hour >= 22;
case AchievementType.speedster:
return record.avgSpeed >= 5;
}
}
}
5.4 通知管理器实现
class NotificationManager {
Future<void> initialize() async {
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
const initializationSettings = InitializationSettings(
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
iOS: DarwinInitializationSettings(),
);
await flutterLocalNotificationsPlugin.initialize(initializationSettings);
}
Future<void> showGoalReminder(int currentSteps, int targetSteps) async {
final remaining = targetSteps - currentSteps;
if (remaining > 0 && remaining <= 1000) {
await flutterLocalNotificationsPlugin.show(
0,
'运动目标提醒',
'距离今日目标还差 $remaining 步,加油!',
const NotificationDetails(
android: AndroidNotificationDetails(
'fitness_channel',
'运动提醒',
importance: Importance.high,
),
),
);
}
}
Future<void> showAchievementUnlocked(Achievement achievement) async {
await flutterLocalNotificationsPlugin.show(
1,
'成就解锁!',
'恭喜解锁「${achievement.type.label}」成就!',
const NotificationDetails(
android: AndroidNotificationDetails(
'achievement_channel',
'成就通知',
importance: Importance.high,
),
),
);
}
}
5.5 数据存储实现
class StorageManager {
Future<void> saveWorkoutRecord(WorkoutRecord record) async {
final prefs = await SharedPreferences.getInstance();
final records = prefs.getStringList('workout_records') ?? [];
records.add(jsonEncode(record.toJson()));
await prefs.setStringList('workout_records', records);
}
Future<List<WorkoutRecord>> loadWorkoutRecords() async {
final prefs = await SharedPreferences.getInstance();
final records = prefs.getStringList('workout_records') ?? [];
return records.map((r) => WorkoutRecord.fromJson(jsonDecode(r))).toList();
}
Future<void> saveDailyGoal(DailyGoal goal) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('daily_goal', jsonEncode(goal.toJson()));
}
Future<DailyGoal> loadDailyGoal() async {
final prefs = await SharedPreferences.getInstance();
final goalStr = prefs.getString('daily_goal');
if (goalStr == null) {
return DailyGoal(
stepTarget: 10000,
calorieTarget: 400,
distanceTarget: 7.0,
createdAt: DateTime.now(),
);
}
return DailyGoal.fromJson(jsonDecode(goalStr));
}
}
六、交互设计
6.1 运动流程
6.2 目标设定流程
6.3 成就解锁流程
七、扩展功能规划
7.1 后续版本规划
7.2 功能扩展建议
7.2.1 社交功能
社交功能:
- 好友排行榜
- 运动挑战赛
- 成就分享
- 运动动态
7.2.2 健康数据整合
整合功能:
- 心率监测
- 睡眠质量
- 体重管理
- 饮水记录
7.2.3 智能分析
分析功能:
- 运动趋势分析
- 健康建议推送
- 目标智能调整
- 运动计划推荐
八、注意事项
8.1 开发注意事项
-
定位权限:确保正确处理定位权限申请和拒绝情况
-
电池优化:长时间定位会消耗大量电量,需优化定位频率
-
数据精度:步数计算需要校准,适应不同用户的步幅
-
隐私保护:位置数据属于敏感信息,需妥善存储和处理
-
后台运行:运动追踪需要支持后台运行,避免被系统终止
8.2 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 步数不准确 | 传感器精度问题 | 结合GPS数据校准 |
| 轨迹断点 | 定位信号丢失 | 增加信号检测和重连 |
| 后台停止 | 系统省电策略 | 申请后台运行权限 |
| 数据丢失 | 应用异常退出 | 实时保存运动数据 |
| 通知不显示 | 权限未授予 | 引导用户开启通知权限 |
8.3 使用技巧
🏃 运动追踪器使用技巧 🏃
运动准备
- 确保手机电量充足
- 开启定位服务
- 授予应用必要权限
- 选择合适的运动模式
运动过程
- 保持手机稳定携带
- 避免频繁查看手机
- 注意运动安全
- 合理安排运动强度
目标达成
- 设定合理的目标
- 坚持每日运动
- 关注成就系统
- 分享运动成果
九、运行说明
9.1 环境要求
| 环境 | 版本要求 |
|---|---|
| Flutter SDK | >= 3.0.0 |
| Dart SDK | >= 2.17.0 |
| 鸿蒙OS | API 21+ |
| Android | API 21+ |
| iOS | 12.0+ |
| Web浏览器 | Chrome 90+ |
9.2 依赖配置
在 pubspec.yaml 中添加以下依赖:
dependencies:
flutter:
sdk: flutter
shared_preferences: ^2.0.0
location: ^4.0.0
flutter_local_notifications: ^15.0.0
wakelock: ^0.6.0
9.3 权限配置
Android (android/app/src/main/AndroidManifest.xml):
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
iOS (ios/Runner/Info.plist):
<key>NSLocationWhenInUseUsageDescription</key>
<string>需要获取您的位置以记录运动轨迹</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>需要获取您的位置以记录运动轨迹</string>
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>
9.4 运行命令
# 查看可用设备
flutter devices
# 运行到Web服务器
flutter run -d web-server -t lib/main_fitness_tracker.dart --web-port 8145
# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 -t lib/main_fitness_tracker.dart
# 运行到Android设备
flutter run -d android -t lib/main_fitness_tracker.dart
# 代码分析
flutter analyze lib/main_fitness_tracker.dart
十、总结
运动步数追踪器应用通过智能算法记录用户每日步数,精确计算消耗卡路里,实时展示运动轨迹,并提供个性化的目标设定和成就激励系统。应用支持步数记录、卡路里计算、轨迹追踪、目标设定、成就系统、历史记录、数据统计、提醒通知八大核心功能。
应用采用 Material Design 3 设计规范,以活力绿色为主色调,象征健康与生机。通过本应用,希望能够帮助用户养成每日运动的好习惯,在运动中收获健康与快乐。
运动步数追踪器——每一步都算数
更多推荐
所有评论(0)