지난포스트에서 StatefulWidget에 대해 알아보고 StatefulWidget 클래스를 만들었습니다.
지금 부터 bmi_scrren.dart파일에 체질량 계산기 화면을 만들려고 합니다.
체질량 계산기의 화면 UI는 미터법과 파운드법을 선택할 수 있는 토글 버튼과 키와 체중을 입력할 수 있는 텍스트 필드 그리고 계산버튼, 마지막으로 결과값을 출력하는 텍스트로 이루어져 있습니다. 이번 포스트에서는 우선 토글 버튼
을 만들어 보도록 하겠습니다.
다음 내용을 다루고 있습니다.
- ToggleButtons 위젯
- EdgeInsets 설정
- late 키워드
- StatefulWidget Lifecycle(initState, build, dispose)
- onPressed와 setState 메소드
토글 버튼 만들기
*하단에 전체 코드가 있으니 전체 코드를 참고하고 싶으시면 아래로 내려 주세요.
먼저 체질량을 계산할 때 넣는 입력값이 미터법인지 파운드법인지 선택하는 토글버튼을 만들도록 하겠습니다. 우선 선언한 변수를 살펴보겠습니다.
result는 체질량 계산 결과값을 담을 변수입니다. isMetric 과 isImperial은 bmi계산시에 미터법과 파운드법의 선택 여부를 담을 부울 값입니다. 미터법을 기본으로 할것이므로 isMetric에 true로 주었습니다. isSelected는 isMetric과 isImperial 담을 리스트이며 ToggleButtons의 위젯의 isSelected 인수에 할당할 것이며 ToggleButtons위젯의 토글 선택 여부(상태)를 담당하게 됩니다.
ToggleButtons 위젯
스캐폴드의 body에는 아래와 같이 Column위젯 안에 Togglebuttons위젯을 넣어주었습니다.
ToggleButtons의 children은 ToggleButtons세트의 각각의 버튼들을 정의합니다. 그리고 버튼의 상태는 isSelected에 의해 제어됩니다. onPressed에서는 각 토글의 동작의 콜백으로 어떤 버튼이 눌렸는지 확인하고 isSelected리스트를 업데이트 할 수 있습니다. ToggleButtons의 구성을 살펴보면 children 매개변수에서 먼저 버튼 개수에 해당하는 Padding위젯을 만들어주었고 child 속성에 Text위젯을 설정해 버튼 이름을 넣어주었습니다.
EdgeInsets으로 padding을 설정해 주었는데, symetric(horizontal: 16)은 왼쪽과 오른쪽으로 16px의 공간을 만들어 줍니다.
EdgeInsets 인스턴스를 만드는 방법은 여러 가지가 존재합니다.
예를 들어 EdgeInset.all(10)은 모든 면에서 10픽셀, EdgeInsets.symmetric(vertical: 10)은 위와 아래 10픽셀, 등 여러 방법이 있습니다.
Padding의 child로 Text위젯을 설정해 주었고, style 인수에 TextStlyle로 fontSize를 18로 주었습니다.
isSelected 인수에서는 토글 버튼 중 어떤 버튼이 선택되었는지 알려주는 부울 값의 List를 넣어주어야 하므로 isSelected를 넣어주었습니다. isSelected의 변수 선언을 보면 late키워드가 써있는걸 알 수 있습니다.
late키워드
isSelected에 late키워드를 넣어준 이유는 현재는 값을 설정할 수 없지만 null이 되지 않게 나중에 설정하겠다는 것을 Flutter에게 알리기 위함입니다.
그럼 isSelected값은 언제 값을 설정해야 할까요? 위젯이 초기화될 때 값을 설정하는 게 바람직할 것 같습니다. 여기서 등장하는 게 스테이트풀 위젯의 라이프사이클입니다.
StatefulWidget Lifecycle
StatefulWidget에는 특정 순서로 호출되는 여러 생명주기 메소드가 있습니다. 이번 포스트에서는 많이 쓰이는 initState, build, dispose메소드에 대해서 알아보도록 하겠습니다.
- initState는 위젯이 호출될 때 한 번 호출됩니다. 일반적으로 State클래스에서 값을 초기화하는 데 사용합니다. 이 메소드는 위젯이 실제로 화면에 그려지기 전에 호출되므로 build메소드 보다 먼저 호출됩니다. 따라서 BuildContext속성에는 접근할 수 없습니다.
- State의 build메소드는 StatelessWIdget의 build메소드와 동일하며 재정의가 항상 필요한 메소드 입니다. 이곳에서 사용자 인터페이스를 생성하고 initState메소드 이후에 해당 상태를 호출할 때마다 트리거 됩니다.
- dispose메소드는 위젯이 위젯 트리에서 제거되기 직전에 호출됩니다. 따라서 dispose메소드를 사용하여 해제해야 하는 리소스를 정리할 수 있습니다.
이제 소스 내에서 initState를 넣어보도록 하겠습니다.
initState메소드에서 isSelected를 isMetric 과 isImperial값을 사용하도록 설정해 주었습니다. 이제 ToggleButtons위젯의 inSelected속성에서 초기화된 isSelected값을 이용할 수 있을 것입니다.
onPressed와 setState호출
ToggleButtons위젯의 마지막 단계는 onPressed 속성을 설정하는 것입니다. onPressed에서 버튼이 토글됐을때 실행되는 콜백 함수를 적용할 수 있습니다. 콜백 함수의 매개변수로 0부터 시작하여 누른 항목 번호 값을 얻을 수 있습니다. 이 함수를 toggleButtons내부에 작성하는 대신에 toggledSelect로 분리하였고 다음과 같습니다.
value가 0이면 "미터법" 버튼을 눌렀음을 의미합니다. 이때는 isMetric값을 true로 설정하고 isImperial 값을 false로 설정 합니다. value가 0이 아니면 두 번째 버튼을 눌렀음을 의미합니다. 0과 반대 작업을 수행하도록 작성하였습니다.
마지막으로 UI 업데이트를 하기 위해서 setState메소드를 호출해야 합니다. setState메소드를 호출하면서 isSelected에 업데이트된 isMetric과 isImperial값을 설정해 줍니다
토글 버튼 코딩이 다 끝났습니다. 전체 코드는 아래와 같습니다.
import 'package:flutter/material.dart';
import 'package:hello_world/shared/menu_bottom.dart';
class BmiScreen extends StatefulWidget {
const BmiScreen({Key? key}) : super(key: key);
@override
State<BmiScreen> createState() => _BmiScreenState();
}
class _BmiScreenState extends State<BmiScreen> {
String result = '';
bool isMetric = true;
bool isImperial = false;
late List<bool> isSelected;
@override
void initState() {
isSelected = [isMetric, isImperial];
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('체질량 계산기')),
body: Column(
children: [
ToggleButtons(
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Text('미터법', style: TextStyle(fontSize: 18))),
Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Text('파운드법', style: TextStyle(fontSize: 18))),
],
isSelected: isSelected,
onPressed: toggleSelect,
),
],
),
bottomNavigationBar: MenuBottom(),
);
}
void toggleSelect(value) {
if (value == 0) {
isMetric = true;
isImperial = false;
} else {
isMetric = false;
isImperial = true;
}
setState(() {
isSelected = [isMetric, isImperial];
});
}
}
앱에서 살펴보겠습니다.
토글 버튼이 잘 작동하네요.
여기까지 수고하셨습니다.
토글 버튼 하나 만드는데도 익혀야 할 개념이 많이 등장하네요.
다음 포스트에서는 텍스트 필드를 만들고 나머지 UI도 추가하도록 하겠습니다.
'프로그래밍 > Flutter' 카테고리의 다른 글
[Flutter] 12. 플러터 패키지(package) 추가하기 (0) | 2022.02.24 |
---|---|
[Flutter] 11. 플러터 체질량 계산기 만들기 (1) | 2022.02.23 |
[Flutter] 9. State, StatelessWidget, StatefulWidget 비교와 만드는 단계 (0) | 2022.02.21 |
[Flutter] 8. BottomNavigationBar(하단 내비게이션 바) (0) | 2022.02.20 |
[Flutter] 7. 내비게이션(Navigation) (0) | 2022.02.19 |
댓글