
在健康管理日益普及的今天,身体质量指数(BMI) 作为衡量体重是否健康的简易指标,已成为大众日常关注的焦点。而一个优秀的 BMI 计算器,不仅要准确计算数值,更应提供清晰的健康解读、友好的交互体验与个性化的视觉适配。
🌐 加入社区 欢迎加入 开源鸿蒙跨平台开发者社区,获取最新资源与技术支持: 👉 开源鸿蒙跨平台开发者社区
完整效果


该应用的核心逻辑简洁而完整:
体重(kg) / (身高(m))²;💡 不仅告诉你“是多少”,更告诉你“意味着什么”。
final height = double.tryParse(heightStr);
final weight = double.tryParse(weightStr);
if (height == null || weight == null || height <= 0 || weight <= 0) {
_showError('请输入有效的正数');
return;
}
double.tryParse() 避免格式错误导致崩溃;ScaffoldMessenger.of(context).showSnackBar() 显示轻量级提示;theme: ThemeData( /* 亮色主题 */ ),
darkTheme: ThemeData( /* 深色主题 */ ),
themeMode: ThemeMode.system, // 跟随系统grey[50],输入框白色;#121212,输入框 #1E1E1E;final isDark = Theme.of(context).brightness == Brightness.dark;
final textColor = isDark ? Colors.white : Colors.black87;
final cardColor = isDark ? const Color(0xFF1E1E1E) : Colors.white;
build 方法中实时判断当前主题;✅ 无障碍设计:高对比度文本 + 清晰图标,照顾不同视觉需求。
OutlineInputBorder(borderSide: BorderSide.none);Icons.height 和 Icons.monitor_weight 直观提示字段含义;按钮 | 类型 | 视觉权重 | 作用 |
|---|---|---|---|
计算 BMI | ElevatedButton | 高(主色填充) | 核心操作 |
重置 | TextButton | 低(文字链接) | 辅助操作 |
Icons.monitor_heart)+ 文案;Card 形式展示结果,包含: AnimatedContainer(
duration: const Duration(milliseconds: 500),
curve: Curves.easeOut,
child: Card(...),
)AnimatedContainer 驱动);技术点 | 应用说明 |
|---|---|
TextEditingController | 精确控制输入框内容,支持清空(clear()) |
SingleChildScrollView | 确保小屏幕设备可滚动查看全部内容 |
CrossAxisAlignment.stretch | 使按钮与输入框宽度一致,布局整齐 |
toStringAsFixed(1) | 保留一位小数,避免冗长数字(如 22.3456 → 22.3) |
Theme.of(context).brightness | 实时获取当前主题亮度,用于动态着色 |
这个 BMI 计算器虽功能简单,却处处体现对用户的尊重与关怀:
import 'package:flutter/material.dart';
void main() {
runApp(const BmiApp());
}
class BmiApp extends StatelessWidget {
const BmiApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
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;
} else if (bmi < 24) {
interpretation = '正常\n继续保持健康的生活方式!';
color = Colors.green;
} else if (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],
),
),
],
),
),
],
),
),
);
}
}