import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: BmiMain(),
);
}
}
class BmiMain extends StatefulWidget {
const BmiMain({Key? key}) : super(key: key);
@override
State<BmiMain> createState() => _BmiMainState();
}
/**
* 사용자의 입력을 받고 값을 검증하기 위한 페이지
*/
class _BmiMainState extends State<BmiMain> {
final _formKey = GlobalKey<FormState>();
// 키와 몸무게의 값을 가져오는 각 컨트롤러 인스턴스를 준비
final _heightController = TextEditingController();
final _weightController = TextEditingController();
/**
* 다 사용한 컨트롤러의 인스턴스는 반드시 화면이 종료될 때 dispose()메서드로 해제제 */
@override
void dispose(){
_heightController.dispose();
_weightController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("BMI 계산기"),
),
body: Container(
padding: const EdgeInsets.all(16.0),
child: Form( // 폼
key: _formKey, // 키 할당
child: Column(
children: [
TextFormField(
decoration: InputDecoration( // 외곽선이 있고 힌트로 '키'를 표시
border: OutlineInputBorder(),
hintText: '키',
),
controller: _heightController, // 입력한 값을 컨트롤러를 통해 얻어옴
keyboardType: TextInputType.number, // 숫자만 입력 가능
validator: (value){
// 입력한 값의 앞뒤 공백을 제거한 것이 비었다면 에러 메시지 표시
if(value?.trim()?.isEmpty ?? true){
return "키를 입력하세요.";
}
return null; // null 을 리턴하면 에러가 없는 상태
},
),
SizedBox(
height: 16.0,
),
TextFormField(
decoration: InputDecoration( // 외곽선이 있고 힌트로 '키'를 표시
border: OutlineInputBorder(),
hintText: '몸무게',
),
controller: _weightController,
keyboardType: TextInputType.number, // 숫자만 입력 가능
validator: (value){
// 입력한 값의 앞뒤 공백을 제거한 것이 비었다면 에러 메시지 표시
if(value?.trim()?.isEmpty ?? true){
return "몸무게게를입력하세요.";
}
return null; // null 을 리턴하면 에러가 없는 상태
},
),
Container(
margin: const EdgeInsets.only(top: 16.0),
alignment: Alignment.centerRight,
child: ElevatedButton(
onPressed: (){
// 폼에 입력된 값 검증 - 키와 몸무게 값이 검증되었다면 화면 이동
if(_formKey?.currentState?.validate() ?? true){
// 검증시 처리
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => BmiResult(
double.parse(_heightController.text.trim()),
double.parse(_weightController.text.trim()),
),
),
);
}
},
child: Text("결과"),
),
),
],
),
),
),
);
}
}
/**
* 결과를 보여주는 페이지
* - 결과를 보여준 이후에는 변경되지 않기 때문에 StatelessWidget 클래스로 작성
*/
class BmiResult extends StatelessWidget {
// StatelessWidget 내부에는 변경이 없는 final 상수만 존재
late final double height; // 초기값 선언을 미룸
late final double weight;
BmiResult(this.height, this.weight); // 키와 몸무게를 받는 생성자
@override
Widget build(BuildContext context) {
final bmi = weight / ((height / 100) * (height / 100));
print("BMI : $bmi");
return Scaffold(
appBar: AppBar(
title: Text("비만도 계산기"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
_calcBmi(bmi), // 계산 결과에 따른 결과 문자열
style: TextStyle(
fontSize: 36
),
),
SizedBox(
height: 16,
),
_buildIcon(bmi), // 계산 결과에 따른 아이콘
],
),
),
);
}
String _calcBmi(double bmi){
String result = "저체중";
if(bmi >= 35){
result = "고도비만";
} else if (bmi >= 30) {
result = '2단계 비만';
} else if (bmi >= 25) {
result = '1단계 비만';
} else if (bmi >= 23) {
result = '과체중';
} else if (bmi >= 18.5) {
result = '정상';
}
return result;
}
Widget _buildIcon(double bmi){
if(bmi >= 23){
return Icon(
Icons.sentiment_very_dissatisfied,
color: Colors.red,
size: 100,
);
} else if(bmi >= 18.5){
return Icon(
Icons.sentiment_satisfied,
color: Colors.green,
size: 100,
);
} else {
return Icon(
Icons.sentiment_dissatisfied,
color: Colors.orange,
size: 100,
);
}
}
}