inblog logo
|
나새끼메이커
    TIL (Today I Learned)

    BMI 계산기 - 버튼값 설정하기

    Eungae's avatar
    Eungae
    Dec 23, 2025
    BMI 계산기 - 버튼값 설정하기
    Contents
    BMI 계산기 위젯트리Screen: HomePageStateState FlowNotesScreen : ResultPage1. HomePage에서 관리되어야 할 변수 확인2. HomePage StatefulWidget으로 변경 후 변수 선언

    BMI 계산기 위젯트리

    Screen: HomePage

    • HomePage — home_page.dart
      • Scaffold
        • AppBar
        • Body
          • Padding
            • Column
              • GenderBox — gender_box.dart
              • Spacer
              • SliderBox (HEIGHT) — slide_box.dart
              • Spacer
              • SliderBox (WEIGHT)
              • Spacer
              • ElevatedButton

    State

    • isMale : bool
    • height : double
    • weight : double

    State Flow

    • GenderBox → onGenderChanged → setState
    • SliderBox → onChanged → setState

    Notes

    • 모든 상태는 HomePage가 소유
    • 하위 위젯은 Stateless 유지

    Screen : ResultPage

    • ResultPage
      • Scaffold
        • AppBar
        • Column
          • ResultGauge
          • ResultText
          • OutlinedButton
     
    요런 구조인데.
    내가 어려워하는 부분은 입력되는 값이 변동하는 것을 코드에 반영하는 것.
    이 순서를 기록해보려고 한다.
     

    1. HomePage에서 관리되어야 할 변수 확인

    • 성별 (bool)
    • 키 (double)
    • 몸무게 (double)
     

    2. HomePage StatefulWidget으로 변경 후 변수 선언

    1. class HomePage를 StatefulWidget으로 변경
      1. // 변경 전 class HomePage extends StatelessWidget { // `HomePage` 위에 커서를 올려놓고 ctrl+. , `Convert to StatefulWidget` 선택 @override Widget build(BuildContext context) {
        // 변경 후 class HomePage extends StatefulWidget { @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { @override Widget build(BuildContext context) {
     
    1. 상속 받은 클래스에 변수 선언 및 변경 시 실행될 함수를 정의
      1. class HomePage extends StatefulWidget { @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { bool isMale = true; void onGenderChanged(bool male) { setState(() { isMale = male; }); } double height = 170; void onHeightChanged(double newHeight) { setState(() { height = newHeight; }); } double weight = 70; void onWeightChanged(double newWeight) { setState(() { weight = newWeight; }); } @override Widget build(BuildContext context) {
     
    1. 변수를 각각의 위젯에 넘겨주기
      1. GenderBox
        1. HomePage에 선언된 변수를 GenderBox에 연결하기.
            • 변수 연결 → bool isMale;
            • 함수 연결 → void Function(bool newValue) 타입으로 연결.
            // 변경 전 import 'package:flutter/material.dart'; class GenderBox extends StatelessWidget { @override Widget build(BuildContext context) { return Row( children: [ gender(context, Icons.male, "MALE", true), SizedBox(width: 8), gender(context, Icons.female, "FEMALE", false), ], ); }
            // 변경 후 import 'package:flutter/material.dart'; class GenderBox extends StatelessWidget { GenderBox(this.isMale, this.onChanged); bool isMale; void Function(bool newValue) onChanged; @override Widget build(BuildContext context) { return Row( children: [ gender(context, Icons.male, "MALE", isMale), SizedBox(width: 8), gender(context, Icons.female, "FEMALE", !isMale), ], ); }
        2. Widget gender에서 “터치 시 값이 바뀌도록” 세팅
            • GestureDetector 세팅 : Container에 Wrap with Widget → onTap → onChanged 연결
            • onChanged가 받을 수 있는 변수 설정: bool isMaleBox
            // 변경 전 Widget gender( BuildContext context, IconData icon, String text, bool selected, ) { return Expanded( child: Container( height: 150, decoration: BoxDecoration( border: Border.all(color: Theme.of(context).dividerColor), ), child: Stack( children: [ Positioned( top: 10, left: 10, child: Opacity(opacity: 0.3, child: Icon(icon, size: 80)), ), Positioned( right: 20, bottom: 20, child: Opacity( opacity: selected ? 1 : 0.3, child: Text( text, style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), ), ), ], ), ), ); } }
            // 변경 후 Widget gender( BuildContext context, IconData icon, String text, bool selected, /*bool isMaleBox,*/ ) { return Expanded( child: /*GestureDetector( onTap: () { onChanged(isMaleBox); }, child: */Container( height: 150, decoration: BoxDecoration( border: Border.all(color: Theme.of(context).dividerColor), ), child: Stack( children: [ Positioned( top: 10, left: 10, child: Opacity(opacity: 0.3, child: Icon(icon, size: 80)), ), Positioned( right: 20, bottom: 20, child: Opacity( opacity: selected ? 1 : 0.3, child: Text( text, style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), ), ), ], ), ), ), ); } }
        3. bool isMaleBox가 추가되었으므로 생성자에도 그 자리를 마련.
          1. @override Widget build(BuildContext context) { return Row( children: [ gender(context, Icons.male, "MALE", isMale, /*true*/), SizedBox(width: 8), gender(context, Icons.female, "FEMALE", !isMale, /*false*/), ], ); }
      2. HomePage의 GenderBox 내에 변수 할당하기
        1. @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("BMI CALCULATOR"), centerTitle: true), body: Padding( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 50), child: Column( children: [ GenderBox(/*isMale, onGenderChanged*/), Spacer(), SliderBox(label: 'HEIGHT', value: 170, unit: 'cm'), Spacer(), SliderBox(label: 'WEIGHT', value: 70, unit: 'kg'), Spacer(), SizedBox( width: double.infinity, height: 56, child: ElevatedButton(onPressed: () {}, child: Text("CALCULATE")), ), ], ), ), ); } }
      3. HomePage의 SliderBox 내에 변수 할당하기
        1. @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("BMI CALCULATOR"), centerTitle: true), body: Padding( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 50), child: Column( children: [ GenderBox(isMale, onGenderChanged), Spacer(), SliderBox(label: 'HEIGHT', value: /*height*/, unit: 'cm'), Spacer(), SliderBox(label: 'WEIGHT', value: /*weight*/, unit: 'kg'), Spacer(), SizedBox( width: double.infinity, height: 56, child: ElevatedButton(onPressed: () {}, child: Text("CALCULATE")), ), ], ), ), ); } }
      4. SliderBox에서 onHeightChanged와 onWeightChanged의 함수를 받을 수 있도록 void Function 타입의 변수 추가
        1. import 'package:flutter/material.dart'; class SliderBox extends StatelessWidget { SliderBox({ required this.label, required this.value, required this.unit, /*required this.onChanged,*/ }); String label; double value; String unit; /*void Function(double newValue) onChanged;*/ @override Widget build(BuildContext context) { return Column( children: [ Row( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text(label, style: TextStyle(fontSize: 20)), Spacer(), Text( value.toStringAsFixed(0), style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold), ), Text(unit, style: TextStyle(fontSize: 20)), ], ), Slider(value: value, onChanged: /*onChanged*/, min: 1, max: 300), ], ); } }
      5. HomePage의 SliderBox 내에 변수 추가
          • 변수명: onChanged ← void Function 타입이므로 함수를 호출해야 함.
          • 변수를 통해 호출할 함수명: onHeightChanged , onWeightChanged
          @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text("BMI CALCULATOR"), centerTitle: true), body: Padding( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 50), child: Column( children: [ GenderBox(isMale, onGenderChanged), Spacer(), SliderBox( label: 'HEIGHT', value: height, unit: 'cm', /*onChanged: onHeightChanged,*/ ), Spacer(), SliderBox( label: 'WEIGHT', value: weight, unit: 'kg', /*onChanged: onWeightChanged,*/ ), Spacer(), SizedBox( width: double.infinity, height: 56, child: ElevatedButton(onPressed: () {}, child: Text("CALCULATE")), ), ], ), ), ); } }
     
     
     
    영상을 보고서 따라할 수는 있겠는데, 직접 해보라고 하면 못 하겠다.
    세 번 해보자. 세 번 해보고 안 되면 다섯 번 해보자.
    다섯 번 해보고 안 되면 열 번 해보자.
    다른 방법 없다.
    Share article
    Contents
    BMI 계산기 위젯트리Screen: HomePageStateState FlowNotesScreen : ResultPage1. HomePage에서 관리되어야 할 변수 확인2. HomePage StatefulWidget으로 변경 후 변수 선언

    나새끼메이커

    RSS·Powered by Inblog