본문 바로가기

Flutter-플러터/클론코딩

Flutter Get x - BMI 계산기 코드 읽기

반응형

bmi_calculator_flutter/lib at principal · IsaiasCuvula/bmi_calculator_flutter (github.com)

 

GitHub - IsaiasCuvula/bmi_calculator_flutter: A BMI calculator made with Flutter/Dart and GetX for State Management

A BMI calculator made with Flutter/Dart and GetX for State Management - GitHub - IsaiasCuvula/bmi_calculator_flutter: A BMI calculator made with Flutter/Dart and GetX for State Management

github.com

 

Main dart

import 'package:bmi_calculator_flutter/views/home_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';  //statusBar 설정 임포트 
import 'package:get/route_manager.dart';

void main() {

//statusbar 의 색깔을 검은색으로 설정 ->statusbar는 어플 ui 상단에 상태바
  SystemChrome.setSystemUIOverlayStyle(
    const SystemUiOverlayStyle(statusBarColor: Colors.black),
  );
  
  
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'BMI CALCULATOR',
      home: HomePage(),
    );
  }
}

 

constants.dart - 상수선언 , 

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart'; //구글 폰트 적용 

enum Gender { male, female, none } //열거형 enum 상수일 때 사용하면 좋음 


//색에 관련된 상수값 지정 
final colorGrey = Colors.grey.withOpacity(0.2);
const colorBlue = Color(0xFF2565CC);
const colorDarkBlue = Color(0xFF0A1028);


//UI를 꾸밀 텍스트, 빈칸에 대한 값 만듬 , 언제든 불러올 수 있게 
TextStyle kTextStyleBold(double size) {
  return GoogleFonts.nunito(
    textStyle: TextStyle(
      color: colorDarkBlue,
      fontWeight: FontWeight.w700,
      fontSize: size,
    ),
  );
}

TextStyle kTextStyle(double size) {
  return GoogleFonts.nunito(
    textStyle: TextStyle(
      color: colorDarkBlue,
      fontWeight: FontWeight.w400,
      fontSize: size,
    ),
  );
}

TextStyle kTextStyleBoldWhite(double size) {
  return GoogleFonts.nunito(
    textStyle: TextStyle(
      color: Colors.white,
      fontWeight: FontWeight.w700,
      fontSize: size,
    ),
  );
}

TextStyle kTextStyleWhite(double size) {
  return GoogleFonts.nunito(
    textStyle: TextStyle(
      color: Colors.white,
      fontWeight: FontWeight.w400,
      fontSize: size,
    ),
  );
}

Widget kVerticalSpace(double height) {
  return SizedBox(
    height: height,
  );
}

 

bmi_controller.dart

import 'dart:math';

import 'package:bmi_calculator_flutter/utils/constants.dart';
import 'package:get/get.dart';



//컨트롤러 클래스 이름 BMIController, 중요하지 않은 변수에 대해서는 var 로 추정 자료형타입 사용 
//몸무게, 키 ,bmi 값은 int, double 자료형 사용  

class BMIController extends GetxController {
  var selectedGender = Gender.none.obs;
  var age = 26.obs;
  var selectedHeightIndex = 0.obs;
  var selectedWeightIndex = 0.obs;
  int _weight = 0;
  int _height = 0;
  double bmi = 0.0;
  var result = ''.obs;
  var description = ''.obs;



  void getSelectedHeightIndex(int index, int height) {
    selectedHeightIndex.value = index;
    _height = height;
  }

  void getSelectedWeightIndex(int index, int weight) {
    selectedWeightIndex.value = index;
    _weight = weight;
  }



  void increaseAge() => age++;
  void decreaseAge() {
    if (age.value > 0) age--;
  }

  void selectGender(Gender gender) {
    selectedGender.value == gender;
  }
  
  
//값 계산하는 함수 , 몸무게와 키에 값이 0이 아니고 gender가 none이 아니면 bmi = 무게 
// pow(키/100,2)= pow(a,b)=a의 b제곱
//Gender.none 이면 '성별을 선택해라' 메세지, 키와 무게 값이 없으면 '키와 무게를 입력하세요 메세지' 
  void calculateBMI() {
    if (_height != 0 && _weight != 0 && selectedGender.value != Gender.none) {
      bmi = (_weight / pow(_height / 100, 2));
      _getResult();
    } else if (selectedGender.value == Gender.none) {
      Get.snackbar('Gender', 'Please select gender!');
    } else if (_height == 0) {
      Get.snackbar('Height', 'Height cannot be 0, select a height!');
    } else if (_weight == 0) {
      Get.snackbar('Weight', 'Weight cannot be 0, select a weight!');
    }
  }
  
  
  //_getResult() 이 bmi결과값 

  void _getResult() {
    if (bmi < 18.5) {
      result.value = 'Underweight';
    } else if (bmi > 18.5 && bmi < 24.9) {
      result.value = 'Healthy Weight';
    } else if (bmi > 25.0 && bmi < 29.9) {
      result.value = 'Overweight';
    } else {
      result.value = 'Obesity';
    }
    _getDescription();
  }


//_getDescription 은 조언내용이 bmi값과 같이 노출됨 
  void _getDescription() {
    if (bmi < 18.5) {
      description.value = "You're in the underweight range. "
          "Eating at least 5 portions of a variety of fruit and vegetables every day. Basing meals on potatoes, bread, rice, pasta or other starchy carbohydrates. Having some dairy or dairy alternatives (such as soya drinks and yoghurts). Eating some beans, pulses, fish, eggs, meat and other protein.";
    } else if (bmi > 18.5 && bmi < 24.9) {
      description.value = "A BMI of 18.5 - 24.9 "
          "indicates that you are at healthy weight for your height. By maintaining a healthy weight, you lower your risk of developing serious health problems.";
    } else if (bmi > 25.0 && bmi < 29.9) {
      description.value =
          'Common treatments for overweight include losing weight through healthy eating,being more physically active, and making other changes to your usual habits. Weight-management programs may help some people lose weight or keep from regaining lost weight.';
    } else {
      description.value =
          "A BMI above 30 indicates that a person is morbidly obese and therefore a candidate for bariatric surgery. Bariatric surgery may also be an option for people with a BMI between 35 and 40 who suffer from life-threatening cardiopulmonary problems, diabetes, or other medical problems listed below.";
    }
  }

//초기셋팅창 
  void clearInfo() {
    selectedGender.value = Gender.none;
    age.value = 26;
    selectedHeightIndex.value = 0;
    selectedWeightIndex.value = 0;
    _weight = 0;
    _height = 0;
    bmi = 0.0;
    result.value = '';
  }
}

view

bmi_details.dart

 

import 'package:bmi_calculator_flutter/controllers/bmi_controller.dart';
import 'package:bmi_calculator_flutter/utils/constants.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

class BMIDetail extends StatelessWidget {
  BMIDetail({Key? key}) : super(key: key);
  
  //controller 파일에 있는 BMIController 를 사용한다고 선언하기 
  final BMIController _bmiController = Get.find<BMIController>();

  @override
  Widget build(BuildContext context) {
    return Container(
      height: double.maxFinite * 0.5,
      decoration: const BoxDecoration(
        color: colorBlue,
        borderRadius: BorderRadius.only(
          topRight: Radius.circular(40),
          topLeft: Radius.circular(40),
        ),
      ),
      child: SingleChildScrollView(
        child: Container(
          height: Get.height,
          padding: const EdgeInsets.all(20),
          
          //obx(()) 안에 파일들을 값을 보여주는 칸만들어주기 
          child: Obx(() {
            final String bmi = _bmiController.bmi.toStringAsFixed(1);
            final result = _bmiController.result.value;
            final description = _bmiController.description.value;
            return Column(
              children: [
                Text(
                  "Your BMI is",
                  //텍스트 스타일 불러오기 - 상수 다트파일 임포트 
                  style: kTextStyleWhite(24),
                ),
                kVerticalSpace(25),
                Text(
                  "$bmi kg/m2",
                  style: kTextStyleBoldWhite(30),
                ),
                Text(
                  "($result)",
                  style: kTextStyleWhite(24),
                ),
                kVerticalSpace(25),
                Text(
                  description,
                  style: kTextStyleWhite(18),
                ),
                kVerticalSpace(25),
                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    const Icon(Icons.bookmark_border_rounded,
                        color: Colors.white, size: 26),
                    const SizedBox(width: 10),
                    const Icon(Icons.share, color: Colors.white, size: 26),
                    const SizedBox(width: 10),
                    
                    
                    InkWell(
                      onTap: () {
                        _bmiController.clearInfo();
                        Get.back();
                      },
                      child: Container(
                        height: 40,
                        padding: const EdgeInsets.all(8),
                        decoration: BoxDecoration(
                          color: colorDarkBlue,
                          borderRadius: BorderRadius.circular(40),
                        ),
                        child: Text(
                          'Close',
                          style: kTextStyleWhite(18),
                        ),
                      ),
                    ),
                  ],
                ),
              ],
            );
          }),
        ),
      ),
    );
  }
}

 

 

 

 

View

home_page.dart

import 'package:bmi_calculator_flutter/controllers/bmi_controller.dart';
import 'package:bmi_calculator_flutter/utils/constants.dart';
import 'package:bmi_calculator_flutter/views/bmi_details.dart';
import 'package:bmi_calculator_flutter/widgets/custom_card.dart';
import 'package:bmi_calculator_flutter/widgets/home_widgets/center_card_weight.dart';
import 'package:bmi_calculator_flutter/widgets/home_widgets/weight_info.dart';
import 'package:bmi_calculator_flutter/widgets/home_widgets/male_female_card.dart';
import 'package:bmi_calculator_flutter/widgets/home_widgets/nav_bottom.dart';
import 'package:bmi_calculator_flutter/widgets/home_widgets/height_info.dart';
import 'package:bmi_calculator_flutter/widgets/male_famale_icon_label.dart';
import 'package:bmi_calculator_flutter/widgets/plus_minus_button.dart';
import 'package:bmi_calculator_flutter/widgets/show_weights.dart';
import 'package:bmi_calculator_flutter/widgets/weight_age.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

import '../widgets/home_widgets/age_card.dart';

class HomePage extends StatelessWidget {
  HomePage({Key? key}) : super(key: key);
  final BMIController _bmiController = Get.put(BMIController());

  void _calculateBMIShowResult(BuildContext context) {
    _bmiController.calculateBMI();
    final bmi = _bmiController.bmi;
    if (bmi != 0.0) {
      showModalBottomSheet(
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(40),
        ),
        context: context,
        builder: (ctx) {
          return BMIDetail();
        },
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      extendBody: true,
      bottomNavigationBar: const NavBottom(),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      floatingActionButton: FloatingActionButton(
        backgroundColor: colorDarkBlue,
        onPressed: () => _calculateBMIShowResult(context),
        child: const Text('BMI'),
      ),
      body: SizedBox(
        width: double.maxFinite,
        height: double.maxFinite,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Container(
              padding: const EdgeInsets.all(20.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  kVerticalSpace(44),
                  Text('BMI Calculator', style: kTextStyleBold(24)),
                  kVerticalSpace(24),
                  MaleFemaleCard(),
                  kVerticalSpace(24),
                  const CenterCardWeight(),
                  kVerticalSpace(24),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      WeightInfo(),
                      AgeCard(),
                    ],
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

 

 

 

 

widget 

weight_age.dart

import 'package:flutter/material.dart';
import '../utils/constants.dart';

class WeightAge extends StatelessWidget {
  const WeightAge({Key? key, required this.label, required this.child})
      : super(key: key);

  final String label;
  final Widget child;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          child: Text(
            label,
            style: kTextStyleBold(18),
          ),
        ),
        kVerticalSpace(18),
        child
      ],
    );
  }
}

 

show_weights.dart

import 'package:bmi_calculator_flutter/widgets/weight_age.dart';
import 'package:flutter/material.dart';
import '../utils/constants.dart';
import 'custom_card.dart';

class ShowWeight extends StatelessWidget {
  const ShowWeight({Key? key, required this.child}) : super(key: key);

  final Widget child;

  @override
  Widget build(BuildContext context) {
    return CustomCard(
      color: colorGrey,
      height: 180,
      child: WeightAge(
        label: 'Weight(in kg)',
        child: Container(
          padding: const EdgeInsets.all(16),
          decoration: BoxDecoration(
            color: Colors.grey.withOpacity(0.1),
            borderRadius: BorderRadius.circular(40),
            border: Border.all(
              width: 2,
              color: colorGrey,
            ),
          ),
          child: SizedBox(height: 40, child: child),
        ),
      ),
    );
  }
}

 

plus_minus_button.dart

 

import 'package:flutter/material.dart';

class PlusMinusButton extends StatelessWidget {
  const PlusMinusButton({Key? key, required this.icon}) : super(key: key);

  final IconData icon;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 26,
        height: 26,
        decoration: BoxDecoration(
          border: Border.all(
            width: 3,
            color: Colors.grey,
          ),
        ),
        child: Icon(icon, size: 18),
      ),
    );
  }
}

 

male_famale_icon_label.dart

 

import 'package:flutter/material.dart';
import '../utils/constants.dart';

class MaleFemaleIconLabel extends StatelessWidget {
  const MaleFemaleIconLabel({Key? key, required this.label, required this.icon})
      : super(key: key);

  final String label;
  final IconData icon;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Icon(
          icon,
          
          //삼항연산자 : label== '남성'? 맞으면 오렌지 , 틀리면 핑크 
          color: label == 'Male' ? Colors.orange : Colors.pink,
          size: 100,
        ),
        Text(
          label,
          style: kTextStyleBold(18),
        ),
      ],
    );
  }
}

 

 

custom_card.dart

 

import 'package:bmi_calculator_flutter/utils/constants.dart';
import 'package:flutter/material.dart';

class CustomCard extends StatelessWidget {
  const CustomCard({
    Key? key,
    required this.child,
    this.isCenterCard = false,
    this.height,
    required this.color,
  }) : super(key: key);

  final Widget child;
  final bool isCenterCard;
  final double? height;
  final Color color;

  @override
  Widget build(BuildContext context) {
    final width = MediaQuery.of(context).size.width;
    return Container(
      width: isCenterCard ? width : width * 0.43,
      height: height,
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        border: Border.all(
          width: 3,
          color: color,
        ),
        borderRadius: BorderRadius.circular(20),
      ),
      child: child,
    );
  }
}

 

 

home_widgets/weight_info.dart

 

import 'package:flutter/material.dart';
import '../../controllers/bmi_controller.dart';
import '../../utils/constants.dart';
import '../show_weights.dart';
import 'package:get/get.dart';

class WeightInfo extends StatelessWidget {
  WeightInfo({Key? key}) : super(key: key);

  final BMIController _bmiController = Get.find<BMIController>();

  @override
  Widget build(BuildContext context) {
    return ShowWeight(
      child: ListView.builder(
        scrollDirection: Axis.horizontal,
        itemCount: 100,
        itemBuilder: (ctx, index) {
          final weight = 40 + index;
          return Center(
            child: InkWell(
              onTap: () {
                _bmiController.getSelectedWeightIndex(index, weight);
              },
              child: Obx(() {
                final selectedIndex = _bmiController.selectedWeightIndex.value;
                return Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Text(
                    weight.toString(),
                    style: selectedIndex == index
                        ? kTextStyleBold(24)
                        : kTextStyle(16),
                  ),
                );
              }),
            ),
          );
        },
      ),
    );
  }
}

 

 

scale_ruler.dart

 

import 'package:flutter/material.dart';

class ScaleRuler extends StatelessWidget {
  const ScaleRuler({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 60,
      child: ListView.builder(
        scrollDirection: Axis.horizontal,
        itemCount: 100,
        itemBuilder: (ctx, index) {
          return Center(
            child: Container(
              height: 60,
              width: 1,
              padding: const EdgeInsets.all(8.0),
              margin: const EdgeInsets.all(8.0),
              decoration: BoxDecoration(
                border: Border.all(
                  width: 2.5,
                  color: Colors.black26,
                ),
              ),
            ),
          );
        },
      ),
    );
  }
}

nav_bottom.dart

 

import 'package:flutter/material.dart';
import '../../utils/constants.dart';

class NavBottom extends StatelessWidget {
  const NavBottom({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ClipRRect(
      borderRadius: const BorderRadius.only(
        topLeft: Radius.circular(40.0),
        topRight: Radius.circular(40.0),
      ),
      child: BottomAppBar(
        color: colorBlue,
        shape: const CircularNotchedRectangle(),
        notchMargin: 8.0,
        child: Row(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            IconButton(
              icon: const Icon(
                Icons.show_chart,
                color: Colors.white,
              ),
              onPressed: () {},
            ),
            const SizedBox(width: 48.0),
            IconButton(
              icon: const Icon(
                Icons.filter_list,
                color: Colors.white,
              ),
              onPressed: () {},
            ),
          ],
        ),
      ),
    );
  }
}

 

 

male_female_card.dart

import 'package:bmi_calculator_flutter/controllers/bmi_controller.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../utils/constants.dart';
import '../custom_card.dart';
import '../male_famale_icon_label.dart';

class MaleFemaleCard extends StatelessWidget {
  MaleFemaleCard({Key? key}) : super(key: key);

  final BMIController _bmiController = Get.find<BMIController>();

  @override
  Widget build(BuildContext context) {
    return Obx(() {
      final selectedGender = _bmiController.selectedGender.value;
      return Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          InkWell(
            borderRadius: BorderRadius.circular(20),
            onTap: () {
              _bmiController.selectedGender(Gender.male);
            },
            child: CustomCard(
              color: selectedGender == Gender.male ? colorDarkBlue : colorGrey,
              child: const MaleFemaleIconLabel(
                label: 'Male',
                icon: Icons.male,
              ),
            ),
          ),
          InkWell(
            borderRadius: BorderRadius.circular(20),
            onTap: () {
              _bmiController.selectedGender(Gender.female);
            },
            child: CustomCard(
              color:
                  selectedGender == Gender.female ? colorDarkBlue : colorGrey,
              child: const MaleFemaleIconLabel(
                label: 'Female',
                icon: Icons.female,
              ),
            ),
          ),
        ],
      );
    });
  }
}

height_info.dart

 

import 'package:bmi_calculator_flutter/controllers/bmi_controller.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../utils/constants.dart';

class HeightInfo extends StatelessWidget {
  HeightInfo({Key? key}) : super(key: key);

  final BMIController _bmiController = Get.find<BMIController>();

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 50,
      child: ListView.builder(
        scrollDirection: Axis.horizontal,
        itemCount: 160,
        itemBuilder: (ctx, index) {
          final height = 100 + index;
          return Center(
            child: InkWell(
              onTap: () {
                _bmiController.getSelectedHeightIndex(index, height);
              },
              child: Obx(() {
                final selectedIndex = _bmiController.selectedHeightIndex.value;
                return Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Text(
                    height.toString(),
                    style: selectedIndex == index
                        ? kTextStyleBold(24)
                        : kTextStyle(16),
                  ),
                );
              }),
            ),
          );
        },
      ),
    );
  }
}

center_card_weight.dart

 

import 'package:bmi_calculator_flutter/widgets/home_widgets/scale_ruler.dart';
import 'package:bmi_calculator_flutter/widgets/home_widgets/height_info.dart';
import 'package:flutter/material.dart';
import '../../utils/constants.dart';
import '../custom_card.dart';

class CenterCardWeight extends StatelessWidget {
  const CenterCardWeight({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CustomCard(
      height: 190,
      isCenterCard: true,
      color: colorGrey,
      child: Center(
        child: Column(
          children: [
            Text('Height (in cm)', style: kTextStyleBold(20)),
            HeightInfo(),
            const ScaleRuler(),
          ],
        ),
      ),
    );
  }
}

 

age_card.dart

 

import 'package:bmi_calculator_flutter/controllers/bmi_controller.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../utils/constants.dart';
import '../custom_card.dart';
import '../plus_minus_button.dart';
import '../weight_age.dart';

class AgeCard extends StatelessWidget {
  AgeCard({Key? key}) : super(key: key);

  final BMIController _bmiController = Get.find<BMIController>();

  @override
  Widget build(BuildContext context) {
    return CustomCard(
      height: 180,
      color: colorGrey,
      child: WeightAge(
        label: 'Age',
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            InkWell(
                onTap: () {
                  _bmiController.decreaseAge();
                },
                child: const PlusMinusButton(icon: Icons.remove_sharp)),
            Obx(() {
              final age = _bmiController.age.value;
              return Text('$age', style: kTextStyleBold(40));
            }),
            InkWell(
              onTap: () {
                _bmiController.increaseAge();
              },
              child: const PlusMinusButton(icon: Icons.add),
            ),
          ],
        ),
      ),
    );
  }
}
728x90
반응형