🎯Flutter 跨平台实战:OpenHarmony 健康管理应用 Day3|健康数据录入表单开发

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

🚀 前言

大家好,本篇是 Flutter + OpenHarmony 健康管理应用 开发系列的第三篇笔记。在 Day2 完成底部导航栏与三页面框架搭建的基础上,今天我们聚焦核心功能开发,实现健康录入页面的表单设计,支持姓名、年龄、身高、体重、心率等关键健康数据录入,适配鸿蒙设备交互逻辑,为后续数据存储与可视化功能做准备。全程使用 DevEco Studio 开发,步骤完整、代码可直接运行,适合课程实训、项目作业自查提交,新手也能一键复刻。

💥 本文你能学到

  • Flutter 表单组件 TextField 与控制器 TextEditingController 的使用
  • 多输入项表单布局与键盘适配处理
  • 健康数据录入页面交互设计
  • 鸿蒙端表单渲染与输入调试
  • Flutter 状态管理与资源释放规范

🥝 开发环境

1. 环境信息

  • 开发工具:DevEco Studio
  • 开发语言:Dart
  • 开发框架:Flutter
  • 调试设备:OpenHarmony 手机模拟器
  • 适配平台:OpenHarmony

2. 依赖配置

本阶段无需新增第三方依赖,沿用之前的 pubspec.yaml 配置即可,无需修改

dependencies:
  flutter:
    sdk: flutter

📝 今日核心开发功能

  • 设计健康数据录入表单(姓名 / 年龄 / 身高 / 体重 / 心率)
  • 实现输入框控制器,获取用户输入数据
  • 适配键盘弹出场景,避免输入框遮挡
  • 鸿蒙端表单页面调试与功能验证

✅ 完整可运行核心代码

import 'package:flutter/material.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(),
    );
  }
}

// 主页面:底部导航 + 页面切换(沿用Day2结构)
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(),
    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: "个人中心"),
        ],
      ),
    );
  }
}

// 首页(沿用Day2,无修改)
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)),
      ),
    );
  }
}

// 核心:健康录入页面(Day3新增表单功能)
class HealthInputPage extends StatefulWidget {
  const HealthInputPage({super.key});

  @override
  State<HealthInputPage> createState() => _HealthInputPageState();
}

class _HealthInputPageState extends State<HealthInputPage> {
  // 初始化输入框控制器,用于获取输入内容
  final TextEditingController _nameController = TextEditingController();
  final TextEditingController _ageController = TextEditingController();
  final TextEditingController _heightController = TextEditingController();
  final TextEditingController _weightController = TextEditingController();
  final TextEditingController _heartRateController = TextEditingController();

  @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)),
            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: "请输入您的心率",
              ),
            ),
          ],
        ),
      ),
    );
  }

  // 释放控制器资源,避免内存泄漏
  @override
  void dispose() {
    _nameController.dispose();
    _ageController.dispose();
    _heightController.dispose();
    _weightController.dispose();
    _heartRateController.dispose();
    super.dispose();
  }
}

// 个人中心(沿用Day2,无修改)
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)),
      ),
    );
  }
}

📱 调试与运行完整步骤

  1. 停止 Day2 项目运行
  2. 打开项目 lib/main.dart,修改原有代码(上方有完整代码)
  3. 终端执行依赖同步命令(无新依赖,可选执行)
    flutter pub get
  4. 执行运行命令,选择 OpenHarmony 模拟器设备
    flutter run
  5. 等待编译完成,点击底部「健康录入」,测试各输入框编辑功能,确认键盘弹出时页面可滚动、无遮挡,实验完成

🔐 跨平台适配说明

本次表单开发严格适配 OpenHarmony 系统特性,保障鸿蒙端稳定运行:

  • 使用 SingleChildScrollView 适配鸿蒙设备软键盘,避免输入框被遮挡,交互流畅;
  • 输入框类型精准匹配(数字 / 文本),适配鸿蒙输入法弹出逻辑,无输入异常;
  • 表单布局自适应鸿蒙屏幕尺寸,不同分辨率设备显示无错位、无溢出;
  • 控制器资源规范释放,避免鸿蒙端长时间运行出现内存泄漏。

🧩 常见错误排查

错误现象解决方法
键盘弹出遮挡输入框确认表单外层嵌套 SingleChildScrollView,检查滚动布局无语法错误
数字输入框无法输入检查 keyboardType: TextInputType.number 是否正确配置,重启模拟器重试
输入后数据无法获取确认控制器(如 _nameController)已正确绑定 TextField,无空值初始化
鸿蒙端表单渲染卡顿执行 flutter clean 清理缓存,重启 DevEco Studio 后重新运行

🎨 项目后续规划

Day3 已完成健康数据录入表单开发,后续将按以下节奏推进:

  • Day4:实现健康数据本地持久化存储,完成数据保存与读取功能;
  • Day5:开发健康数据可视化页面,实现数据图表展示;
  • Day6+:表单验证优化、UI 美化、鸿蒙真机适配与项目打包发布。

📌 项目总结

本篇笔记详细记录了基于 DevEco Studio 的 Flutter 鸿蒙项目 Day3 开发全过程,在 Day2 页面框架基础上,完成了健康录入表单的设计与实现,涵盖姓名、年龄、身高、体重、心率等核心健康字段录入功能。通过本次开发,熟练掌握了 Flutter 输入框控制器的使用、表单布局适配技巧以及鸿蒙端交互调试方法,为后续健康数据存储、可视化等功能开发奠定了坚实基础。

✅ 结尾小贴士

  • 文中所有代码可直接复制替换运行,无需额外修改,适配鸿蒙模拟器无压力;
  • 全程仅使用 DevEco Studio 即可完成开发与调试,无需额外安装其他工具;
  • 无需修改 pubspec.yaml,保持默认依赖即可正常运行;
  • 点赞 + 收藏,后续 Day4 健康数据本地存储笔记更新不迷路!

更多推荐