首先app制作完后的界面如下图所示:
第一页:
第二页:
项目的结构如下图所示:
在lib文件夹下边有components和screens两个文件夹
components文件夹下面有
主要是定制化,可重用的组件 如下面的红色按钮,第一页中的块部分,身高体重的可重用的块,圆形的按钮。
screens下面主要是第一页和第二页的结构:
其余三个文件表示的是BMI指标的计算。和程序的主入口
下面是代码部分
input_page.dart
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:bmicalculator/components/reusable_card.dart';
import 'package:bmicalculator/components/icon_content.dart';
import 'package:bmicalculator/constants.dart';
import 'package:bmicalculator/screens/results_page.dart';
import 'package:bmicalculator/components/bottomButton.dart';
import 'package:bmicalculator/components/round_icon_button.dart';
import 'package:bmicalculator/CalculatorBrain.dart';
enum Gender {
male,
female,
}
class InputPage extends StatefulWidget {
@override
_InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
// Color maleCardColour = inactiveCardColour;
// Color femaleCardColour = inactiveCardColour;
Gender selectedGender;
int height = 180;
int weight = 60;
int age = 24;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('BMI CALCILATOR'),
), //AppBar
body: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: ReuseableCard(
onPress: () {
setState(() {
selectedGender = Gender.male;
});
},
colour: selectedGender == Gender.male
? kActiveCardColor
: kInactiveCardColour,
cardChild: new IconContent(
icon: FontAwesomeIcons.mars,
label: 'MALE',
)),
),
Expanded(
child: new ReuseableCard(
onPress: () {
setState(() {
selectedGender = Gender.female;
});
},
colour: selectedGender == Gender.female
? kActiveCardColor
: kInactiveCardColour,
cardChild: new IconContent(
icon: FontAwesomeIcons.venus,
label: 'FEMALE',
)),
),
],
)),
Expanded(
child: new ReuseableCard(
colour: kActiveCardColor,
cardChild: Column(
children: <Widget>[
Text(
'HEIGHT',
style: kLabelTextStyle,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.ideographic,
children: <Widget>[
Text(
height.toString(),
style: TextStyle(
fontSize: 50.0,
fontWeight: FontWeight.w900,
),
),
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,
activeColor: Color(0xFFEB1555),
inactiveColor: Color(0xFF8D8E98),
onChanged: (double newValue) {
setState(() {
height = newValue.round();
});
},
),
),
],
),
),
),
Expanded(
child: Row(
children: <Widget>[
Expanded(
child: new ReuseableCard(
colour: kActiveCardColor,
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,
onPredded: () {
setState(() {
weight--;
});
},
),
SizedBox(
width: 10.0,
),
RoundIconButton(
icon: FontAwesomeIcons.plus,
onPredded: () {
setState(() {
weight++;
});
},
),
],
),
],
),
),
),
Expanded(
child: new ReuseableCard(
colour: kActiveCardColor,
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,
onPredded: () {
setState(() {
age--;
});
},
),
SizedBox(
width: 10.0,
),
RoundIconButton(
icon: FontAwesomeIcons.plus,
onPredded: () {
setState(() {
age++;
});
},
),
],
),
],
),
),
),
],
),
),
BottomButton(
buttonTitle: 'CALCULATE',
onTap: () {
CalculatorBrain calcu =
CalculatorBrain(height: height, weight: weight);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ResultsPage(
bmiResult: calcu.calculateBMI(),
resultText: calcu.getResult(),
interpretation: calcu.getInterpretation(),
),
),
);
},
),
],
),
);
}
}
result_page.dart
import 'package:flutter/material.dart';
import 'package:bmicalculator/constants.dart';
import 'package:bmicalculator/components/reusable_card.dart';
import 'package:bmicalculator/components/bottomButton.dart';
class ResultsPage extends StatelessWidget {
final String bmiResult;
final String resultText;
final String interpretation;
ResultsPage(
{@required this.bmiResult,
@required this.resultText,
@required this.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: ReuseableCard(
colour: kActiveCardColor,
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(
onTap: () {
Navigator.pop(context);
},
buttonTitle: 'RE-CALCULATE')
],
),
);
}
}
componenets/bottombutton.dart
import 'package:flutter/material.dart';
import 'package:bmicalculator/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: kBottomContainerColor,
margin: EdgeInsets.only(top: 10.0),
padding: EdgeInsets.only(bottom: 20.0),
width: double.infinity,
height: kBottomContainerHeight,
),
);
}
}
componenst/icon_button.dart
import 'package:flutter/material.dart';
import 'package:bmicalculator/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,
), //Icon
SizedBox(
height: 15.0,
),
Text(
label,
style: kLabelTextStyle,
)
],
);
}
}
components/reusablue_card.dart
import 'package:flutter/material.dart';
class ReuseableCard extends StatelessWidget {
ReuseableCard({@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)),
),
);
}
}
components/round_icon_button.dart
import 'package:flutter/material.dart';
class RoundIconButton extends StatelessWidget {
RoundIconButton({@required this.icon, @required this.onPredded});
final Function onPredded;
final IconData icon;
@override
Widget build(BuildContext context) {
return RawMaterialButton(
child: Icon(icon),
onPressed: onPredded,
elevation: 0.0,
disabledElevation: 6.0,
constraints: BoxConstraints.tightFor(
width: 56.0,
height: 56.0,
),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
fillColor: Color(0xFF4C4F5E),
);
}
}
contants.dart
import 'package:flutter/material.dart';
const kBottomContainerHeight = 80.0;
const kActiveCardColor = Color(0xFF1D1E33);
const kInactiveCardColour = Color(0xFF111328);
const kBottomContainerColor = 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,
);
CalculatorBrain.dart
import 'package:flutter/material.dart';
import 'dart:math';
class CalculatorBrain {
CalculatorBrain({@required this.height, @required this.weight});
final int height;
final int weight;
double _bmi;
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';
}
}
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';
}
}
}
main.dart
import 'package:flutter/material.dart';
import 'package:bmicalculator/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(),
); //MaterialApp
}
}