news 2026/6/10 19:49:07

Flutter for OpenHarmony BMI 健康计算器:打造支持深色模式的智能健康工具

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Flutter for OpenHarmony BMI 健康计算器:打造支持深色模式的智能健康工具

Flutter for OpenHarmony BMI 健康计算器:打造支持深色模式的智能健康工具

在健康管理日益普及的今天,身体质量指数(BMI)作为衡量体重是否健康的简易指标,已成为大众日常关注的焦点。而一个优秀的 BMI 计算器,不仅要准确计算数值,更应提供清晰的健康解读、友好的交互体验与个性化的视觉适配

🌐 加入社区 欢迎加入开源鸿蒙跨平台开发者社区,获取最新资源与技术支持: 👉开源鸿蒙跨平台开发者社区


完整效果

一、核心功能:从输入到健康建议

该应用的核心逻辑简洁而完整:

  1. 用户输入:身高(cm)、体重(kg);
  2. 数据校验:非空、正数、有效数字;
  3. BMI 计算:公式为体重(kg) / (身高(m))²
  4. 健康分级
    • < 18.5:偏瘦(橙色提示)
    • 18.5–23.9:正常(绿色鼓励)
    • 24–27.9:超重(橙红警示)
    • ≥ 28:肥胖(红色警告)
  5. 结果展示:大号数值 + 个性化健康建议。

💡 不仅告诉你“是多少”,更告诉你“意味着什么”。


二、智能输入处理与错误反馈

1. 安全解析用户输入

finalheight=double.tryParse(heightStr);finalweight=double.tryParse(weightStr);if(height==null||weight==null||height<=0||weight<=0){_showError('请输入有效的正数');return;}

2. 即时错误提示


三、双主题系统:自动适配用户偏好

1. 主题定义

theme:ThemeData(/* 亮色主题 */),darkTheme:ThemeData(/* 深色主题 */),themeMode:ThemeMode.system,// 跟随系统

2. 动态颜色获取

finalisDark=Theme.of(context).brightness==Brightness.dark;finaltextColor=isDark?Colors.white:Colors.black87;finalcardColor=isDark?constColor(0xFF1E1E1E):Colors.white;

无障碍设计:高对比度文本 + 清晰图标,照顾不同视觉需求。


四、UI/UX 设计亮点

1. 输入体验优化

2. 按钮层级分明

按钮类型视觉权重作用
计算 BMIElevatedButton高(主色填充)核心操作
重置TextButton低(文字链接)辅助操作

3. 结果区域动态呈现

4. 平滑动画过渡

AnimatedContainer(duration:constDuration(milliseconds:500),curve:Curves.easeOut,child:Card(...),)

五、技术实现细节

技术点应用说明
TextEditingController精确控制输入框内容,支持清空(clear()
SingleChildScrollView确保小屏幕设备可滚动查看全部内容
CrossAxisAlignment.stretch使按钮与输入框宽度一致,布局整齐
toStringAsFixed(1)保留一位小数,避免冗长数字(如 22.3456 → 22.3)
Theme.of(context).brightness实时获取当前主题亮度,用于动态着色

六、扩展与应用场景

可扩展方向

应用场景


七、结语:小工具,大关怀

这个 BMI 计算器虽功能简单,却处处体现对用户的尊重与关怀

import'package:flutter/material.dart';voidmain(){runApp(const BmiApp());}class BmiApp extends StatelessWidget{const BmiApp({super.key});@override Widget build(BuildContext context){returnMaterialApp(debugShowCheckedModeBanner: false, title:'📏 BMI 计算器', theme: ThemeData(brightness: Brightness.light, primarySwatch: Colors.blue, scaffoldBackgroundColor: Colors.grey[50], inputDecorationTheme: const InputDecorationTheme(filled: true, fillColor: Colors.white, border: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(12)), borderSide: BorderSide.none,),),), darkTheme: ThemeData(brightness: Brightness.dark, primarySwatch: Colors.blue, scaffoldBackgroundColor: const Color(0xFF121212), inputDecorationTheme: const InputDecorationTheme(filled: true, fillColor: Color(0xFF1E1E1E), border: OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(12)), borderSide: BorderSide.none,),),), themeMode: ThemeMode.system, home: const BmiCalculatorScreen(),);}}class BmiCalculatorScreen extends StatefulWidget{const BmiCalculatorScreen({super.key});@override State<BmiCalculatorScreen>createState()=>_BmiCalculatorScreenState();}class _BmiCalculatorScreenState extends State<BmiCalculatorScreen>{final TextEditingController _heightController=TextEditingController();final TextEditingController _weightController=TextEditingController();double? _bmi;String _interpretation='';Color _resultColor=Colors.blue;void_calculateBMI(){final heightStr=_heightController.text.trim();final weightStr=_weightController.text.trim();if(heightStr.isEmpty||weightStr.isEmpty){_showError('请输入身高和体重');return;}final height=double.tryParse(heightStr);final weight=double.tryParse(weightStr);if(height==null||weight==null||height<=0||weight<=0){_showError('请输入有效的正数');return;}// 身高从 cm 转为 m final heightInMeters=height /100;final bmi=weight /(heightInMeters * heightInMeters);String interpretation;Color color;if(bmi<18.5){interpretation='偏瘦\n建议增加营养摄入,保持规律作息。';color=Colors.orange;}elseif(bmi<24){interpretation='正常\n继续保持健康的生活方式!';color=Colors.green;}elseif(bmi<28){interpretation='超重\n建议适当运动,控制饮食。';color=Colors.orangeAccent;}else{interpretation='肥胖\n建议咨询医生,制定科学减重计划。';color=Colors.red;}setState((){ _bmi=bmi;_interpretation=interpretation;_resultColor=color;});} void _showError(String message){ ScaffoldMessenger.of(context).showSnackBar(SnackBar(content:Text(message)),);}void_reset(){_heightController.clear();_weightController.clear();setState((){ _bmi=null;_interpretation='';_resultColor=Colors.blue;});} @override Widget build(BuildContext context){ final isDark=Theme.of(context).brightness==Brightness.dark;final textColor=isDark?Colors.white:Colors.black87;final cardColor=isDark?const Color(0xFF1E1E1E):Colors.white;return Scaffold(appBar:AppBar(title:const Text('BMI 健康计算器'),centerTitle:true,backgroundColor:Colors.transparent,elevation:0,),body:SingleChildScrollView(padding:const EdgeInsets.all(24),child:Column(crossAxisAlignment:CrossAxisAlignment.stretch,children:[//输入区域 TextField(controller:_heightController,keyboardType:TextInputType.numberWithOptions(decimal:true),decoration:InputDecoration(labelText:'身高(cm)',hintText:'例如:175',prefixIcon:const Icon(Icons.height),),),const SizedBox(height:16),TextField(controller:_weightController,keyboardType:TextInputType.numberWithOptions(decimal:true),decoration:InputDecoration(labelText:'体重(kg)',hintText:'例如:70',prefixIcon:const Icon(Icons.monitor_weight),),),const SizedBox(height:24),//计算按钮 ElevatedButton.icon(onPressed:_calculateBMI,icon:const Icon(Icons.calculate),label:const Text('计算 BMI',style:TextStyle(fontSize:18)), style: ElevatedButton.styleFrom(padding: const EdgeInsets.symmetric(vertical:16), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12),),),), const SizedBox(height:16), // 重置按钮(轻量) TextButton(onPressed: _reset, child: const Text('重置', style: TextStyle(fontSize:16)),), const SizedBox(height:32), // 结果区域if(_bmi!=null)AnimatedContainer(duration: const Duration(milliseconds:500), curve: Curves.easeOut, child: Card(color: cardColor, elevation:4, child: Padding(padding: const EdgeInsets.all(24), child: Column(children:[Text('你的 BMI', style: TextStyle(fontSize:18, color: Colors.grey[600]?? Colors.grey,),), const SizedBox(height:8), Text(_bmi!.toStringAsFixed(1), style: TextStyle(fontSize:48, fontWeight: FontWeight.bold, color: _resultColor,),), const SizedBox(height:16), Text(_interpretation, textAlign: TextAlign.center, style: TextStyle(fontSize:18, height:1.5, color: textColor,),),],),),),),if(_bmi==null)Center(child: Column(mainAxisAlignment: MainAxisAlignment.center, children:[const Icon(Icons.monitor_heart, size:80, color: Colors.grey), const SizedBox(height:16), Text('输入身高和体重\n开始计算你的 BMI', textAlign: TextAlign.center, style: TextStyle(fontSize:18, color: isDark ? Colors.grey[500]:Colors.grey[600],),),],),),],),),);}}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 11:37:41

国内进口的车膜品牌推荐几家

开篇&#xff1a;定下基调随着国内汽车消费升级&#xff0c;进口车膜凭借成熟的技术工艺与稳定的品质表现&#xff0c;成为众多车主提升车辆防护与驾乘体验的首选。但市场上品牌繁杂、优劣难辨&#xff0c;给车主带来了选择困境。本次测评针对国内主流进口车膜品牌展开专业对比…

作者头像 李华
网站建设 2026/6/10 11:33:58

MathCAD许可证与其他软件集成

在科研、教育和工程领域&#xff0c;MathCAD作为一款卓越的数学计算和工程设计软件&#xff0c;经常需要与其他软件协同工作。然而&#xff0c;许可证管理在不同软件之间的集成可能会成为一个挑战。本文将探讨MathCAD许可证与其他软件集成的问题&#xff0c;并介绍如何实现无缝…

作者头像 李华
网站建设 2026/6/10 13:17:47

软考一次过的概率大吗?看完通过率分析,你就明白了!

软考因其报名条件宽松、高级也以考代评等优点&#xff0c;每年吸引近百万人报名参加。 有些第一次来考的考生&#xff0c;因为急着拿证&#xff0c;所以想知道软考一次过的概率有多大。 这篇文章&#xff0c;小希将通过分析软考的通过率来为大家解答这个问题。 一、软考整体…

作者头像 李华
网站建设 2026/6/10 13:18:29

决胜国自然:专业PPT与配图,如何为您的申报“画龙点睛”

国家自然科学基金会议评审是项目申请能否获批的关键环节。在这一阶段&#xff0c;高质量的PPT不仅是项目科学价值和创新性的“放大器”&#xff0c;更是研究团队学术水准、严谨态度与协同能力的“立体名片”。许多科研人员面临一个共同困境&#xff1a;掌握了前沿的科学思想和扎…

作者头像 李华
网站建设 2026/6/10 13:17:14

2026国自然模板大改,无从下笔?

作为常年参与国自然申报工作的科研人员&#xff0c;今年基金委发布2026国自然申请书改版通知后&#xff0c;我感受到了明显的调整压力。往年可按固定模块填空完成的申请书&#xff0c;今年被砍掉了所有固定章节&#xff0c;仅保留立项依据、研究内容、研究基础三大核心板块&…

作者头像 李华
网站建设 2026/6/10 13:22:01

java对象排序

在 Java 中&#xff0c;对象排序主要通过两种接口实现&#xff1a;自然排序&#xff08;Comparable&#xff09; 和 定制排序&#xff08;Comparator&#xff09;。它们分别适用于不同的场景&#xff0c;下面详细对比和说明。 自然排序&#xff1a;java.lang.Comparable定制排序…

作者头像 李华