Flutter for OpenHarmony实战DAY3:从零搭建健康管家App之新增手动更改健康数据功能,完整本地持久化业务逻辑
在上一篇文章中,我们完成了健康管家 App 的数据可视化图表(步数、心率、睡眠趋势图)。但一个完整的健康 App,必须支持用户手动管理自己的健康数据。本篇将带你实现:✅ 手动录入健康数据(步数、心率、睡眠时长)✅ 编辑已有数据✅ 删除不需要的数据✅ 本地持久化存储(重启 App 数据不丢失)✅ 数据与图表页面自动联动✅ 表单校验 + 用户友好提示✅ 兼容 Flutter + OpenHarmony
Flutter for OpenHarmony实战DAY3:从零搭建健康管家App之新增手动更改健康数据功能,完整本地持久化业务逻辑
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
前言
在上一篇文章中,我们完成了健康管家 App 的数据可视化图表(步数、心率、睡眠趋势图)。
但一个完整的健康 App,必须支持用户手动管理自己的健康数据。
本篇将带你实现:
✅ 手动录入健康数据(步数、心率、睡眠时长)
✅ 编辑已有数据
✅ 删除不需要的数据
✅ 本地持久化存储(重启 App 数据不丢失)
✅ 数据与图表页面自动联动
✅ 表单校验 + 用户友好提示
✅ 兼容 Flutter + OpenHarmony 鸿蒙双平台
一、功能说明
本功能模块包含以下核心能力:
- 数据录入:用户输入步数、心率、睡眠时长,自动记录当前日期
- 数据编辑:点击编辑按钮,快速修改已有记录
- 数据删除:一键删除无用记录
- 本地存储:使用 shared_preferences 实现数据持久化
- 数据校验:防止空数据、无效数据提交
- 列表展示:清晰展示所有历史健康记录
- 图表联动:录入的数据自动同步到数据统计页面
二、添加项目依赖
在 pubspec.yaml 中添加依赖:
dependencies:
flutter:
sdk: flutter
# 图表(上一篇已添加)
fl_chart: ^0.65.0
# 本地持久化存储
shared_preferences: ^2.5.3
# 时间格式化
intl: ^0.19.0
执行命令安装依赖:
flutter pub get
三、完整核心代码实现
3.1 健康数据管理页面(录入 + 编辑 + 删除)
新建文件:pages/health_record_page.dart
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';
import 'package:intl/intl.dart';
class HealthRecordPage extends StatefulWidget {
const HealthRecordPage({super.key});
@override
State<HealthRecordPage> createState() => _HealthRecordPageState();
}
class _HealthRecordPageState extends State<HealthRecordPage> {
// 健康数据列表
List<Map<String, dynamic>> _healthRecords = [];
// 输入框控制器
final TextEditingController _stepController = TextEditingController();
final TextEditingController _heartController = TextEditingController();
final TextEditingController _sleepController = TextEditingController();
// 标记当前是否为编辑状态
int? _editIndex;
@override
void initState() {
super.initState();
// 页面初始化时加载本地数据
_loadLocalData();
}
// 从本地加载健康数据
Future<void> _loadLocalData() async {
final prefs = await SharedPreferences.getInstance();
final String? dataStr = prefs.getString("health_records");
if (dataStr != null) {
setState(() {
_healthRecords = List<Map<String, dynamic>>.from(json.decode(dataStr));
});
}
}
// 保存数据到本地
Future<void> _saveLocalData() async {
final prefs = await SharedPreferences.getInstance();
prefs.setString("health_records", json.encode(_healthRecords));
}
// 提交数据(新增 / 编辑)
void _submitData() {
// 获取输入内容并校验
final int step = int.tryParse(_stepController.text) ?? 0;
final int heart = int.tryParse(_heartController.text) ?? 0;
final double sleep = double.tryParse(_sleepController.text) ?? 0.0;
if (step <= 0 || heart <= 0 || sleep <= 0) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("请输入有效的健康数据!")),
);
return;
}
// 构建数据模型
final Map<String, dynamic> newRecord = {
"date": DateFormat("yyyy-MM-dd").format(DateTime.now()),
"step": step,
"heartRate": heart,
"sleepTime": sleep,
};
setState(() {
if (_editIndex != null) {
// 编辑模式
_healthRecords[_editIndex!] = newRecord;
_editIndex = null;
} else {
// 新增模式
_healthRecords.add(newRecord);
}
});
// 保存到本地
_saveLocalData();
// 清空输入框
_clearInput();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(_editIndex != null ? "修改成功!" : "添加成功!")),
);
}
// 编辑数据
void _editData(int index) {
final item = _healthRecords[index];
_stepController.text = item["step"].toString();
_heartController.text = item["heartRate"].toString();
_sleepController.text = item["sleepTime"].toString();
setState(() {
_editIndex = index;
});
}
// 删除数据
void _deleteData(int index) {
setState(() {
_healthRecords.removeAt(index);
});
_saveLocalData();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("删除成功!")),
);
}
// 清空输入框
void _clearInput() {
_stepController.clear();
_heartController.clear();
_sleepController.clear();
setState(() {
_editIndex = null;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("健康数据管理"),
centerTitle: true,
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 标题
const Text(
"添加 / 编辑健康数据",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
// 步数输入
TextField(
controller: _stepController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: "今日步数",
border: OutlineInputBorder(),
),
),
const SizedBox(height: 10),
// 心率输入
TextField(
controller: _heartController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: "静息心率(次/分)",
border: OutlineInputBorder(),
),
),
const SizedBox(height: 10),
// 睡眠时长输入
TextField(
controller: _sleepController,
keyboardType: TextInputType.numberWithOptions(decimal: true),
decoration: const InputDecoration(
labelText: "睡眠时长(小时)",
border: OutlineInputBorder(),
),
),
const SizedBox(height: 16),
// 按钮区域
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: _submitData,
child: Text(_editIndex == null ? "添加记录" : "保存修改"),
),
OutlinedButton(
onPressed: _clearInput,
child: const Text("清空"),
),
],
),
const Divider(height: 30, thickness: 1),
// 历史记录列表
const Text(
"历史健康记录",
style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Expanded(
child: _healthRecords.isEmpty
? const Center(child: Text("暂无记录,快去添加吧~"))
: ListView.builder(
itemCount: _healthRecords.length,
itemBuilder: (context, index) {
final item = _healthRecords[index];
return Card(
margin: const EdgeInsets.symmetric(vertical: 6),
child: ListTile(
title: Text("${item['date']} | 步数:${item['step']}"),
subtitle: Text(
"心率:${item['heartRate']} 次/分 | 睡眠:${item['sleepTime']}h",
),
trailing: SizedBox(
width: 100,
child: Row(
children: [
IconButton(
icon: const Icon(Icons.edit, color: Colors.blue),
onPressed: () => _editData(index),
),
IconButton(
icon: const Icon(Icons.delete, color: Colors.red),
onPressed: () => _deleteData(index),
),
],
),
),
),
);
},
),
),
],
),
),
);
}
}
3.2 主页面底部导航加入入口(main.dart)
import 'package:flutter/material.dart';
import 'pages/home_page.dart';
import 'pages/data_page.dart';
import 'pages/health_record_page.dart';
import 'pages/setting_page.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '健康管家',
theme: ThemeData(primarySwatch: Colors.blue, useMaterial3: true),
debugShowCheckedModeBanner: false,
home: const MainPage(),
);
}
}
class MainPage extends StatefulWidget {
const MainPage({super.key});
@override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
int _currentIndex = 0;
final List<Widget> _pages = [
const HomePage(),
const DataPage(),
const HealthRecordPage(), // 数据管理页
const SettingPage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
body: _pages[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
type: BottomNavigationBarType.fixed,
onTap: (index) => setState(() => _currentIndex = index),
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: "首页"),
BottomNavigationBarItem(icon: Icon(Icons.bar_chart), label: "统计"),
BottomNavigationBarItem(icon: Icon(Icons.edit_note), label: "记录"),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: "设置"),
],
),
);
}
}
3.3 图表页面自动读取录入数据(data_page.dart 关键代码)
// 加载本地健康数据,与录入页面完全联动
Future<void> _loadData() async {
final prefs = await SharedPreferences.getInstance();
final data = prefs.getString("health_records");
if (data != null) {
setState(() {
healthData = List<Map<String, dynamic>>.from(json.decode(data));
});
}
}
四、功能运行效果
- 录入数据:填写步数、心率、睡眠,点击添加记录
- 编辑数据:点击列表编辑图标,自动填充输入框,修改后保存
- 删除数据:点击删除图标,一键移除并同步本地存储
- 数据持久化:关闭重启 App,数据依然保留
- 图表联动:进入统计页面,自动展示录入的数据趋势


五、代码亮点(CSDN 高赞必备)
- 完整业务逻辑:真正实现增删改查,不是单纯 UI 演示
- 本地持久化:使用行业通用 shared_preferences
- 数据校验:防止非法输入,提升用户体验
- 组件封装:代码结构清晰,易于维护和扩展
- 双平台兼容:完美支持 Android /iOS/ OpenHarmony 鸿蒙
- 注释齐全:每一个核心方法都配有详细注释
六、常见问题解决
- 依赖报错
执行:
flutter clean
flutter pub get
- 图表不显示
确保先录入数据,图表页面下拉刷新即可加载 - 数据不保存
检查 shared_preferences 依赖是否正常安装 - 鸿蒙运行报错
使用 DevEco Studio 打开项目,重新同步 Flutter 模块
总结
本篇我们完成了健康管家 App最核心的业务功能:
✅ 健康数据录入
✅ 数据编辑
✅ 数据删除
✅ 本地存储
✅ 图表联动
项目已经具备完整 App 的基础架构
更多推荐



所有评论(0)