Make a BMI Calculator App with Flutter
What This App Does
A BMI Calculator app serves a specific need in today's mobile-first world. Building one with Flutter means you ship to iOS, Android, and the web from a single codebase, cutting development time dramatically while keeping a native-quality experience.
Main Features
| Feature | Why It Matters |
|---|---|
| Height & Weight Input | Sliders or text fields for metric/imperial units with instant validation |
| BMI Calculation Engine | Formula: weight (kg) / height (m)^2, categorised into underweight, normal, overweight, obese |
| History & Trends | Store past results locally and show a chart of BMI over time |
How to Make a BMI Calculator App with Flutter
Height & Weight Input
class InputCard extends StatelessWidget {
final String label;
final double value;
final double min, max;
final String unit;
final ValueChanged onChanged;
const InputCard({super.key, required this.label, required this.value,
required this.min, required this.max, required this.unit,
required this.onChanged});
@override
Widget build(BuildContext context) {
return Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(label, style: Theme.of(context).textTheme.titleMedium),
const SizedBox(height: 8),
Row(
children: [
Expanded(
child: Slider(
value: value, min: min, max: max,
divisions: (max - min).round(),
label: value.toStringAsFixed(1),
onChanged: onChanged,
),
),
SizedBox(width: 72,
child: Text('${value.toStringAsFixed(1)} $unit',
textAlign: TextAlign.end,
style: Theme.of(context).textTheme.bodyLarge),
),
],
),
],
),
),
);
}
}
BMI Calculation Engine
class BmiCalculator {
static double calculate({required double weightKg, required double heightCm}) {
final heightM = heightCm / 100;
return weightKg / (heightM * heightM);
}
static ({String label, Color color, int riskLevel}) categorise(double bmi) {
if (bmi < 18.5) return (label: 'Underweight', color: Colors.blue, riskLevel: 1);
if (bmi < 25) return (label: 'Normal', color: Colors.green, riskLevel: 0);
if (bmi < 30) return (label: 'Overweight', color: Colors.orange, riskLevel: 2);
return (label: 'Obese', color: Colors.red, riskLevel: 3);
}
}
History & Trends
class BmiRecord {
final DateTime date; final double bmi;
BmiRecord({required this.date, required this.bmi});
Map toJson() => {'date': date.toIso8601String(), 'bmi': bmi};
factory BmiRecord.fromJson(Map json) => BmiRecord(
date: DateTime.parse(json['date']), bmi: (json['bmi'] as num).toDouble());
}
class BmiHistory {
static const _key = 'bmi_history';
static Future> load() async {
final prefs = await SharedPreferences.getInstance();
final raw = prefs.getString(_key);
if (raw == null) return [];
return (jsonDecode(raw) as List).map((e) => BmiRecord.fromJson(e)).toList();
}
static Future save(List records) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(_key, jsonEncode(records.map((r) => r.toJson()).toList()));
}
}
Recommended Libraries
| Package | Purpose |
|---|---|
| flutter_form_builder | Pre-built form fields and validators |
| shared_preferences | Persist BMI history as JSON |
| fl_chart | Trend line chart of past BMI records |
UI & UX Suggestions
Use a teal primary, amber secondary, category colours colour palette to match the app's purpose. Keep the navigation simple — a bottom nav bar or a single-scroll layout works best for this type of app. Make sure every interaction provides haptic or visual feedback so the app feels responsive and polished.