1
0
mirror of https://github.com/nisrulz/flutter-examples.git synced 2025-11-09 04:58:58 +00:00

BMI calculator example (#130)

This commit is contained in:
lutaii
2023-10-12 18:08:26 +02:00
committed by GitHub
parent f761e553e4
commit 36c8bed38c
19 changed files with 780 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
import 'package:flutter/material.dart';
import '../palette.dart';
class CalculateButton extends StatelessWidget {
const CalculateButton({
super.key,
required this.onTap,
});
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height / 12,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Palette.action,
),
child: TextButton(
style: ButtonStyle(
overlayColor:
MaterialStateProperty.all(Colors.white.withOpacity(0.10)),
),
onPressed: onTap,
child: const Text(
'CALCULATE YOUR BMI',
style: TextStyle(
color: Palette.textActive,
fontSize: 20,
),
),
),
);
}
}

View File

@@ -0,0 +1,105 @@
import 'package:bmi_calculator/calculator/calculate_button.dart';
import 'package:flutter/material.dart';
import 'package:bmi_calculator/calculator/height_widget.dart';
import 'package:bmi_calculator/calculator/int_picker_widget.dart';
import 'package:bmi_calculator/calculator/sex_widget.dart';
import 'package:bmi_calculator/result/result_page.dart';
import 'package:bmi_calculator/body_model.dart';
import 'package:bmi_calculator/palette.dart';
class CalculatorBody extends StatefulWidget {
const CalculatorBody({
super.key,
required this.model,
});
final BodyModel model;
@override
State<CalculatorBody> createState() => _CalculatorBodyState();
}
class _CalculatorBodyState extends State<CalculatorBody> {
@override
Widget build(BuildContext context) {
return Container(
color: Palette.background,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SexWidget(
sex: widget.model.sex,
onMaleTap: () => setState(() {
// Set sex to male
widget.model.sex = Sex.male;
}),
onFemaleTap: () => setState(() {
// Set sex to female
widget.model.sex = Sex.female;
})),
HeightWidget(
height: widget.model.height,
onHeightChanged: (height) => setState(() {
// Set height and round to Int
widget.model.height = height.toInt();
}),
),
SizedBox(
height: (MediaQuery.of(context).size.width - 48) / 2,
child: Row(
children: [
Expanded(
// Weight widget
child: IntPickerWidget(
title: 'Weight',
onIncreaseTap: () => setState(() {
// Increase weight
widget.model.weight++;
}),
onDecreaseTap: () => setState(() {
// Decrease weight
widget.model.weight--;
}),
value: widget.model.weight,
),
),
const SizedBox(
width: 5,
),
Expanded(
// Age widget
child: IntPickerWidget(
title: 'Age',
onIncreaseTap: () => setState(() {
// Increase age
widget.model.age++;
}),
onDecreaseTap: () => setState(() {
// Decrease age
widget.model.age--;
}),
value: widget.model.age,
),
)
],
),
),
CalculateButton(
onTap: () {
// Navigate to Result Page
Navigator.push(
context,
MaterialPageRoute(
builder: ((context) => ResultPage(model: widget.model)),
),
);
},
),
],
),
),
);
}
}

View File

@@ -0,0 +1,31 @@
import 'package:bmi_calculator/calculator/calculator_body.dart';
import 'package:flutter/material.dart';
import 'package:bmi_calculator/body_model.dart';
import 'package:bmi_calculator/palette.dart';
class CalculatorPage extends StatelessWidget {
CalculatorPage({
Key? key,
required this.title,
}) : super(key: key);
final String title;
final BodyModel model = BodyModel(
sex: Sex.male,
height: 183,
weight: 74,
age: 19,
);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
backgroundColor: Palette.background,
),
body: CalculatorBody(model: model),
);
}
}

View File

@@ -0,0 +1,83 @@
import 'package:flutter/material.dart';
import '../palette.dart';
class HeightWidget extends StatelessWidget {
const HeightWidget({
super.key,
required this.height,
required this.onHeightChanged,
});
final int height;
final Function(double) onHeightChanged;
@override
Widget build(BuildContext context) {
return Container(
height: (MediaQuery.of(context).size.width - 48) / 2,
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Palette.cardBackgroundInactive,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'HEIGHT',
style: TextStyle(
fontSize: 23,
fontWeight: FontWeight.w600,
color: Palette.textInactive,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Text(
height.round().toString(),
style: const TextStyle(
fontSize: 50,
fontWeight: FontWeight.w800,
color: Palette.textActive,
),
),
const Text(
'cm',
style: TextStyle(
fontSize: 30,
color: Palette.textInactive,
),
),
],
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 24.0,
),
child: SliderTheme(
data: SliderTheme.of(context).copyWith(
trackHeight: 1.0,
thumbShape: const RoundSliderThumbShape(
enabledThumbRadius: 15,
),
),
child: Slider(
value: height.toDouble(),
min: 150.0,
max: 210.0,
activeColor: Palette.textActive,
inactiveColor: Palette.textInactive,
thumbColor: Palette.action,
onChanged: onHeightChanged,
),
),
),
],
),
);
}
}

View File

@@ -0,0 +1,84 @@
import 'package:bmi_calculator/palette.dart';
import 'package:flutter/material.dart';
class IntPickerWidget extends StatelessWidget {
const IntPickerWidget({
super.key,
required this.title,
required this.onIncreaseTap,
required this.onDecreaseTap,
required this.value,
});
final String title;
final VoidCallback onIncreaseTap;
final VoidCallback onDecreaseTap;
final int value;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Palette.cardBackgroundInactive,
),
height: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
title.toUpperCase(),
style: const TextStyle(
fontSize: 23,
fontWeight: FontWeight.w600,
color: Palette.textInactive,
),
),
Text(
value.toString(),
style: const TextStyle(
fontSize: 50,
fontWeight: FontWeight.w800,
color: Palette.textActive,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
InkWell(
onTap: onDecreaseTap,
child: Container(
width: 56,
height: 56,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Palette.cardBackgroundActive,
),
child: const Icon(
Icons.remove,
color: Palette.textActive,
),
),
),
InkWell(
onTap: onIncreaseTap,
child: Container(
width: 56,
height: 56,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Palette.cardBackgroundActive,
),
child: const Icon(
Icons.add,
color: Palette.textActive,
),
),
),
],
),
],
),
);
}
}

View File

@@ -0,0 +1,103 @@
import 'package:bmi_calculator/palette.dart';
import 'package:flutter/material.dart';
import '../body_model.dart';
class SexWidget extends StatelessWidget {
const SexWidget({
super.key,
required this.sex,
required this.onMaleTap,
required this.onFemaleTap,
});
final Sex sex;
final VoidCallback onMaleTap;
final VoidCallback onFemaleTap;
@override
Widget build(BuildContext context) {
return SizedBox(
height: (MediaQuery.of(context).size.width - 48) / 2,
child: Row(
children: [
Expanded(
child: GestureDetector(
onTap: onMaleTap,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: sex == Sex.male
? Palette.cardBackgroundActive
: Palette.cardBackgroundInactive,
),
height: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.male_rounded,
size: 100,
color: sex == Sex.male
? Palette.textActive
: Palette.textInactive,
),
Text(
'MALE',
style: TextStyle(
fontSize: 23,
fontWeight: FontWeight.w600,
color: sex == Sex.male
? Palette.textActive
: Palette.textInactive,
),
),
],
),
),
),
),
const SizedBox(
width: 5,
),
Expanded(
child: GestureDetector(
onTap: onFemaleTap,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: sex == Sex.female
? Palette.cardBackgroundActive
: Palette.cardBackgroundInactive,
),
height: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.female_rounded,
size: 100,
color: sex == Sex.female
? Palette.textActive
: Palette.textInactive,
),
Text(
'FEMALE',
style: TextStyle(
fontSize: 23,
fontWeight: FontWeight.w600,
color: sex == Sex.female
? Palette.textActive
: Palette.textInactive,
),
),
],
),
),
),
)
],
),
);
}
}