Flutter 跨平台实战OpenHarmony 健康管理应用 Day5引入本地存储 新增性别单选选项欢迎加入开源鸿蒙跨平台社区https://openharmonycrossplatform.csdn.net 前言大家好本篇是Flutter OpenHarmony 健康管理应用开发系列的第五篇笔记。在 Day4 完成表单非空校验与提交提示功能的基础上今天主要完成两大核心任务第一引入shared_preferences第三方本地持久化存储依赖第二在健康录入表单中新增性别单选选项使用 Radio 单选按钮实现男女选择并将性别信息和其他健康数据一起保存到本地实现关闭应用重启后数据不丢失。全程适配 OpenHarmony 鸿蒙模拟器步骤完整、代码可直接复制运行适合课程实训作业提交自查分值高、结构规范。 本文你能学到Flutter 第三方依赖shared_preferences引入与配置pubspec.yaml 依赖添加规范写法Radio 单选按钮组件实现性别选择功能单选按钮状态管理与选中值获取多表单字段包含性别一起本地存储保存鸿蒙端第三方依赖适配与编译运行方法 开发环境1. 环境信息开发工具DevEco Studio开发语言Dart开发框架Flutter调试设备OpenHarmony 手机模拟器适配平台OpenHarmony2. 依赖配置Day5 需要新增本地存储依赖手动修改pubspec.yamldependencies: flutter: sdk: flutter shared_preferences: ^2.2.2 今日核心开发功能配置并引入 shared_preferences 本地持久化存储依赖健康录入页面新增性别男女单选按钮组件实现性别选中状态管理与值获取提交时连同姓名、年龄、身高、体重、心率、性别一起校验合法信息全部保存到本地存储适配鸿蒙布局单选组件显示正常无错乱✅ 完整可运行核心代码import package:flutter/material.dart; import package:shared_preferences/shared_preferences.dart; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); override Widget build(BuildContext context) { return MaterialApp( title: 鸿蒙健康管理, debugShowCheckedModeBanner: false, theme: ThemeData(primarySwatch: Colors.blue), home: const MainPage(), ); } } class MainPage extends StatefulWidget { const MainPage({super.key}); override StateMainPage createState() _MainPageState(); } class _MainPageState extends StateMainPage { int _currentIndex 0; final ListWidget _pages const [ HomePage(), HealthInputPage(), ProfilePage(), ]; void _onItemTapped(int index) { setState(() { _currentIndex index; }); } override Widget build(BuildContext context) { return Scaffold( body: _pages[_currentIndex], bottomNavigationBar: BottomNavigationBar( currentIndex: _currentIndex, onTap: _onItemTapped, items: const [ BottomNavigationBarItem(icon: Icon(Icons.home), label: 首页), BottomNavigationBarItem(icon: Icon(Icons.add_chart), label: 健康录入), BottomNavigationBarItem(icon: Icon(Icons.person), label: 个人中心), ], ), ); } } class HomePage extends StatelessWidget { const HomePage({super.key}); override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(首页)), body: const Center( child: Text(欢迎使用健康管理应用, style: TextStyle(fontSize: 18)), ), ); } } class HealthInputPage extends StatefulWidget { const HealthInputPage({super.key}); override StateHealthInputPage createState() _HealthInputPageState(); } class _HealthInputPageState extends StateHealthInputPage { final TextEditingController _nameController TextEditingController(); final TextEditingController _ageController TextEditingController(); final TextEditingController _heightController TextEditingController(); final TextEditingController _weightController TextEditingController(); final TextEditingController _heartRateController TextEditingController(); String _gender 男; // 保存方法带第三方库 必弹提示 Futurevoid _saveData() async { String name _nameController.text.trim(); String age _ageController.text.trim(); String height _heightController.text.trim(); String weight _weightController.text.trim(); String heart _heartRateController.text.trim(); // 不填写 → 必提示 if (name.isEmpty || age.isEmpty || height.isEmpty || weight.isEmpty || heart.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text(请填写完整信息)), ); return; } // 保存到本地存储第三方库 SharedPreferences prefs await SharedPreferences.getInstance(); await prefs.setString(name, name); await prefs.setString(age, age); await prefs.setString(height, height); await prefs.setString(weight, weight); await prefs.setString(heart, heart); await prefs.setString(gender, _gender); // 保存成功 → 必提示 ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text(✅ 数据保存成功)), ); } override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(健康录入)), body: SingleChildScrollView( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text(姓名, style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500)), const SizedBox(height: 8), TextField( controller: _nameController, decoration: const InputDecoration(border: OutlineInputBorder(), hintText: 请输入姓名), ), const SizedBox(height: 16), const Text(性别, style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500)), Row( children: [ Expanded( child: ListTile( title: const Text(男), leading: RadioString( value: 男, groupValue: _gender, onChanged: (val) { setState(() { _gender val!; }); }, ), ), ), Expanded( child: ListTile( title: const Text(女), leading: RadioString( value: 女, groupValue: _gender, onChanged: (val) { setState(() { _gender val!; }); }, ), ), ), ], ), const SizedBox(height: 16), const Text(年龄, style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500)), const SizedBox(height: 8), TextField( controller: _ageController, keyboardType: TextInputType.number, decoration: const InputDecoration(border: OutlineInputBorder(), hintText: 请输入年龄), ), const SizedBox(height: 16), const Text(身高(cm), style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500)), const SizedBox(height: 8), TextField( controller: _heightController, keyboardType: TextInputType.number, decoration: const InputDecoration(border: OutlineInputBorder(), hintText: 请输入身高), ), const SizedBox(height: 16), const Text(体重(kg), style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500)), const SizedBox(height: 8), TextField( controller: _weightController, keyboardType: TextInputType.number, decoration: const InputDecoration(border: OutlineInputBorder(), hintText: 请输入体重), ), const SizedBox(height: 16), const Text(心率(次/分), style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500)), const SizedBox(height: 8), TextField( controller: _heartRateController, keyboardType: TextInputType.number, decoration: const InputDecoration(border: OutlineInputBorder(), hintText: 请输入心率), ), const SizedBox(height: 30), SizedBox( width: double.infinity, height: 50, child: ElevatedButton( onPressed: _saveData, child: const Text(保存数据, style: TextStyle(fontSize: 18)), ), ), ], ), ), ); } override void dispose() { _nameController.dispose(); _ageController.dispose(); _heightController.dispose(); _weightController.dispose(); _heartRateController.dispose(); super.dispose(); } } class ProfilePage extends StatelessWidget { const ProfilePage({super.key}); override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text(个人中心)), body: const Center(child: Text(个人信息展示区域, style: TextStyle(fontSize: 16))), ); } } 调试与运行完整步骤停止上一个项目运行打开项目根目录pubspec.yaml添加 shared_preferences 依赖终端执行依赖安装命令flutter pub get打开lib/main.dart修改原有代码上方有完整代码终端执行运行命令flutter run选择 OpenHarmony 模拟器编译完成后进入健康录入页面测试选择性别、填写全部信息点击保存提示存储成功关闭应用重新打开数据可后续读取实验完成 跨平台适配说明本次 Day5 新增依赖与单选组件完美适配 OpenHarmony 鸿蒙系统shared_preferences 第三方依赖兼容鸿蒙编译环境无适配报错Radio 单选按钮布局自适应鸿蒙屏幕点击选中状态切换正常页面滚动布局依旧适配软键盘弹出不会遮挡单选区域与输入框本地存储逻辑在鸿蒙端正常生效数据持久化保存稳定可靠。 常见错误排查错误现象解决方法导入 shared_preferences 报错检查 pubspec.yaml 依赖格式执行 flutter pub get 重新拉取依赖单选按钮无法切换选中确认 onChanged 中调用 setState 更新 _gender 变量选择性别仍提示未选择检查初始默认值是否设置校验逻辑是否包含性别判空编译提示依赖版本冲突使用文中指定版本号执行 flutter clean 后重新运行 项目后续规划Day5 已完成本地依赖引入、性别单选功能与全字段本地保存后续规划Day6实现首页自动读取本地存储健康数据并展示Day7个人中心页面回显已保存的姓名、性别、身体指标信息Day8新增清空本地数据、重置表单功能继续按任务规划依次完成 UI 美化、BMI 计算、图表可视化等功能 项目总结本篇笔记完整记录了 Flutter 鸿蒙健康管理项目 Day5 开发全过程完成了第三方本地存储依赖配置、性别单选按钮开发、全表单数据连同性别一起本地持久化保存的功能。熟练掌握了 pubspec 依赖配置、Radio 单选状态管理、异步本地存储写入、多字段联合校验等核心知识点同时兼容 OpenHarmony 鸿蒙端运行适配为后续数据读取展示、个人中心回显等功能筑牢基础。✅ 结尾小贴士先改 pubspec.yaml 再加依赖必须执行 flutter pub get 才可以正常导入代码可直接全覆盖使用无需额外修改逻辑点赞收藏不迷路后续每日开发笔记持续同步更新