본문 바로가기
프로그래밍/Flutter

[Flutter] 10. 토글 버튼 만들기(ToggleButtons)

by 신나요 2022. 2. 22.

지난포스트에서 StatefulWidget 대해 알아보고 StatefulWidget 클래스를 만들었습니다.

 

지금 부터 bmi_scrren.dart파일에 체질량 계산기 화면을 만들려고 합니다.

체질량 계산기의 화면 UI 미터법과 파운드법을 선택할 수 있는 토글 버튼과 키와 체중을 입력할  있는 텍스트 필드 그리고 계산버튼, 마지막으로 결과값을 출력하는 텍스트로 이루어져 있습니다. 이번 포스트에서는 우선 토글 버튼

을 만들어 보도록 하겠습니다.

 

다음 내용을 다루고 있습니다.

  1. ToggleButtons 위젯
  2. EdgeInsets 설정
  3. late 키워드
  4. StatefulWidget Lifecycle(initState, build, dispose)
  5. 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 패딩설정

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메소드에 대해서 알아보도록 하겠습니다.

  1. initState는 위젯이 호출될 때 한 번 호출됩니다. 일반적으로 State클래스에서 값을 초기화하는 데 사용합니다. 이 메소드는 위젯이 실제로 화면에 그려지기 전에 호출되므로 build메소드 보다 먼저 호출됩니다. 따라서 BuildContext속성에는 접근할 수 없습니다.
  2. State의 build메소드는 StatelessWIdget의 build메소드와 동일하며 재정의가 항상 필요한 메소드 입니다. 이곳에서 사용자 인터페이스를 생성하고 initState메소드 이후에 해당 상태를 호출할 때마다 트리거 됩니다.
  3. 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 추가하도록 하겠습니다.

댓글