GitHub - londonappbrewery/BMI-Calculator-Flutter-Completed: The completed code for the BMI Project - The Complete Flutter Develo
The completed code for the BMI Project - The Complete Flutter Development Bootcamp - GitHub - londonappbrewery/BMI-Calculator-Flutter-Completed: The completed code for the BMI Project - The Complet...
github.com
MVC모델로 나누기
코드 리뷰
테마는 검은색
전체적인 위젯은 Expanded 위젯을 사용, 화면을 분할시킴
화면 분활된 곳에 ReusableCard를 만들어서 분할 된 화면에 재사용함
기본으로 제공되는 키, 몸무게, 나이는 180, 60, 20
키는 슬라이더 위젯을 사용해서 (최소 120cm, 최대 220cm)로 지정
몸무게와 나이는 +,- 버튼을 이용해서 사용하게 함
정보를 입력하는 페이지와
결과를 보여주는 페이지를 나눔
해당 주어진 정보를 다 입력하고 '계산' 버튼을 누르면 결과 페이지로 이동하는 것
BMI 결과뿐만 아니라
해당 BMI에 대한 조언도 같이 나오게 해놓음
Main dart
- 전체적인 컬러가 검은색
import 'package:flutter/material.dart';
import 'package:bmi_calculator/screens/input_page.dart';
void main() => runApp(BMICalculator());
class BMICalculator extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
primaryColor: Color(0xFF0A0E21),
scaffoldBackgroundColor: Color(0xFF0A0E21),
),
home: InputPage(),
);
}
}
Model
-input
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:bmi_calculator/components/icon_content.dart';
import 'package:bmi_calculator/components/reusable_card.dart';
import 'package:bmi_calculator/constants.dart';
import 'package:bmi_calculator/screens/results_page.dart';
import 'package:bmi_calculator/components/bottom_button.dart';
import 'package:bmi_calculator/components/round_icon_button.dart';
import 'package:bmi_calculator/calculator_brain.dart';
enum Gender {
male,
female,
}
class InputPage extends StatefulWidget {
@override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
Gender selectedGender;
int height = 180;
int weight = 60;
int age = 20;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
onPress: () {
setState(() {
selectedGender = Gender.male;
});
},
colour: selectedGender == Gender.male ? kActiveCardColour: kInactiveCardColour,
cardChild: IconContent(
icon: FontAwesomeIcons.mars,
label: 'MALE',
),
),
),
Expanded(
child: ReusableCard(
onPress: () {
setState(() {
selectedGender = Gender.female;
});
},
colour: selectedGender == Gender.female ? kActiveCardColour : kInactiveCardColour,
cardChild: IconContent(
icon: FontAwesomeIcons.venus,
label: 'FEMALE',
),
),
),
],
)),
Expanded(
child: ReusableCard(
colour: kActiveCardColour,
cardChild: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'HEIGHT',
style: kLabelTextStyle,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: <Widget>[
Text(
height.toString(),
style: kNumberTextStyle,
),
Text(
'cm',
style: kLabelTextStyle,
)
],
),
SliderTheme(
data: SliderTheme.of(context).copyWith(
inactiveTrackColor: Color(0xFF8D8E98),
activeTrackColor: Colors.white,
thumbColor: Color(0xFFEB1555),
overlayColor: Color(0x29EB1555),
thumbShape:
RoundSliderThumbShape(enabledThumbRadius: 15.0),
overlayShape:
RoundSliderOverlayShape(overlayRadius: 30.0),
),
child: Slider(
value: height.toDouble(),
min: 120.0,
max: 220.0,
onChanged: (double newValue) {
setState(() {
height = newValue.round();
});
},
),
),
],
),
),
),
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReusableCard(
colour: kActiveCardColour,
cardChild: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'WEIGHT',
style: kLabelTextStyle,
),
Text(
weight.toString(),
style: kNumberTextStyle,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RoundIconButton(
icon: FontAwesomeIcons.minus,
onPressed: () {
setState(() {
weight--;
});
}),
SizedBox(
width: 10.0,
),
RoundIconButton(
icon: FontAwesomeIcons.plus,
onPressed: () {
setState(() {
weight++;
});
},
),
],
),
],
),
),
),
Expanded(
child: ReusableCard(
colour: kActiveCardColour,
cardChild: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'AGE',
style: kLabelTextStyle,
),
Text(
age.toString(),
style: kNumberTextStyle,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RoundIconButton(
icon: FontAwesomeIcons.minus,
onPressed: () {
setState(
() {
age--;
},
);
},
),
SizedBox(
width: 10.0,
),
RoundIconButton(
icon: FontAwesomeIcons.plus,
onPressed: () {
setState(() {
age++;
});
})
],
)
],
),
),
),
],
),
),
BottomButton(
buttonTitle: 'CALCULATE',
onTap: () {
CalculatorBrain calc =
CalculatorBrain(height: height, weight: weight);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ResultsPage(
bmiResult: calc.calculateBMI(),
resultText: calc.getResult(),
interpretation: calc.getInterpretation(),
),
),
);
},
),
],
),
);
}
}
model
- result
import 'package:flutter/material.dart';
import 'package:bmi_calculator/constants.dart';
import 'package:bmi_calculator/components/reusable_card.dart';
import 'package:bmi_calculator/components/bottom_button.dart';
class ResultsPage extends StatelessWidget {
ResultsPage(
{@required this.interpretation,
@required this.bmiResult,
@required this.resultText});
final String bmiResult;
final String resultText;
final String interpretation;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCULATOR'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Container(
padding: EdgeInsets.all(15.0),
alignment: Alignment.bottomLeft,
child: Text(
'Your Result',
style: kTitleTextStyle,
),
),
),
Expanded(
flex: 5,
child: ReusableCard(
colour: kActiveCardColour,
cardChild: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
resultText.toUpperCase(),
style: kResultTextStyle,
),
Text(
bmiResult,
style: kBMITextStyle,
),
Text(
interpretation,
textAlign: TextAlign.center,
style: kBodyTextStyle,
),
],
),
),
),
BottomButton(
buttonTitle: 'RE-CALCULATE',
onTap: () {
Navigator.pop(context);
},
)
],
),
);
}
}
View
- BottomButton ->
- IconContent
- ReusableButton
- RoundIconButton
import 'package:flutter/material.dart';
import 'package:bmi_calculator/constants.dart';
class BottomButton extends StatelessWidget {
BottomButton({@required this.onTap, @required this.buttonTitle});
final Function onTap;
final String buttonTitle;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
child: Center(
child: Text(
buttonTitle,
style: kLargeButtonTextStyle,
),
),
color: kBottomContainerColour,
margin: EdgeInsets.only(top: 10.0),
padding: EdgeInsets.only(bottom: 20.0),
width: double.infinity,
height: kBottomContainerHeight,
),
);
}
}
import 'package:flutter/material.dart';
import 'package:bmi_calculator/constants.dart';
class IconContent extends StatelessWidget {
IconContent({this.icon, this.label});
final IconData icon;
final String label;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
icon,
size: 80.0,
),
SizedBox(
height: 15.0,
),
Text(
label,
style: kLabelTextStyle,
)
],
);
}
}
import 'package:flutter/material.dart';
class ReusableCard extends StatelessWidget {
ReusableCard({@required this.colour, this.cardChild, this.onPress});
final Color colour;
final Widget cardChild;
final Function onPress;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPress,
child: Container(
child: cardChild,
margin: EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: colour,
borderRadius: BorderRadius.circular(10.0),
),
),
);
}
}
import 'package:flutter/material.dart';
class RoundIconButton extends StatelessWidget {
RoundIconButton({@required this.icon, @required this.onPressed});
final IconData icon;
final Function onPressed;
@override
Widget build(BuildContext context) {
return RawMaterialButton(
elevation: 0.0,
child: Icon(icon),
onPressed: onPressed,
constraints: BoxConstraints.tightFor(
width: 56.0,
height: 56.0,
),
shape: CircleBorder(),
fillColor: Color(0xFF4C4F5E),
);
}
}
Controll
import 'dart:math';
class CalculatorBrain {
CalculatorBrain({this.height, this.weight});
final int height;
final int weight;
double _bmi;
String calculateBMI() {
_bmi = weight / pow(height / 100, 2);
return _bmi.toStringAsFixed(1);
}
String getResult() {
if (_bmi >= 25) {
return 'Overweight';
} else if (_bmi > 18.5) {
return 'Normal';
} else {
return 'Underweight';
}
}
String getInterpretation() {
if (_bmi >= 25) {
return 'You have a higher than normal body weight. Try to exercise more.';
} else if (_bmi >= 18.5) {
return 'You have a normal body weight. Good job!';
} else {
return 'You have a lower than normal body weight. You can eat a bit more.';
}
}
}
상수
- 디자인 관련
import 'package:flutter/material.dart';
const kBottomContainerHeight = 80.0;
const kActiveCardColour = Color(0xFF1D1E33);
const kInactiveCardColour = Color(0xFF111328);
const kBottomContainerColour = Color(0xFFEB1555);
const kLabelTextStyle = TextStyle(
fontSize: 18.0,
color: Color(0xFF8D8E98),
);
const kNumberTextStyle = TextStyle(
fontSize: 50.0,
fontWeight: FontWeight.w900,
);
const kLargeButtonTextStyle = TextStyle(
fontSize: 25.0,
fontWeight: FontWeight.bold,
);
const kTitleTextStyle = TextStyle(
fontSize: 50.0,
fontWeight: FontWeight.bold,
);
const kResultTextStyle = TextStyle(
color: Color(0xFF24D876),
fontSize: 22.0,
fontWeight: FontWeight.bold,
);
const kBMITextStyle = TextStyle(
fontSize: 100.0,
fontWeight: FontWeight.bold,
);
const kBodyTextStyle = TextStyle(
fontSize: 22.0,
);
'Flutter-플러터 > 클론코딩' 카테고리의 다른 글
플러터 계산기 코드 11.6 (0) | 2022.11.06 |
---|---|
flutter 계산기 코드 읽기!! (0) | 2022.11.01 |
todo 코드 읽기 연습 (0) | 2022.10.23 |
Flutter Get x - BMI 계산기 코드 읽기 (1) | 2022.10.15 |
GET X로 만든 계산기 어플 읽기 (0) | 2022.10.07 |