플러터 (flutter)

Flutter Stateful 위젯 (StatefulWidget)

CreatoMaestro 2023. 6. 24. 06:50
반응형

이 글에서는 flutter의 statefulwidget에 대해 알아본다.

 

지금까지는 flutter에 대해 알아보면서 StatelessWidget만을 사용해왔다.

StatelessWidget은 상태가 없는 위젯으로 한 번 화면에 띄워지면 다시 바뀌지 않는 위젯이다.

(즉, 단 한번만 build가 된다. 절대로 재실행되지 않는다.)

 

이와는 반대로 StatefulWidget은 상태를 가진다.

앱이 실행되면서 변수 값 등이 바뀌면서 상태가 바뀌면 StatefulWidget은 그에 맞게 변화한다.

 

상태가 바뀌어 있는 상태를 dirty 상태라고 하고 이 상태가 되면 StatefulWidget은 build()를 다시 실행한다.

그러고 나면 clean 상태가 된다. 

이 상태에서 widget이 변경되거나, state가 변경되면 다시 dirty 상태로 돌아간다.

 

아래 그림은 StatefulWidget의 생명 주기이다.

StatefulWidget 생명주기
StatefulWidget 생명주기

지금부터는 StatefulWidget을 활용한 앱을 제작해본다.

StatefulWidget을 활용하여 만들 앱은 기본적인 카운터이다.

앱 실행 결과
프로젝트 결과

Down 버튼은 숫자를 1씩 줄어들게 하고, Up 버튼은 1씩 늘어나게 한다.

Reset은 숫자를 0으로 초기화한다.

 

전체 코드는 다음과 같다.

import 'package:flutter/material.dart';

void main() {
  runApp(CounterPage());
}

class CounterPage extends StatefulWidget{
  CounterPage({Key? key}): super(key: key);

  @override
  State<CounterPage> createState()=> _CounterPageState();

}

class _CounterPageState extends State<CounterPage> {

  int _count=0;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              Text(
                "$_count",
                style: const TextStyle(
                  fontSize: 30.0
                ),
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  OutlinedButton(
                      onPressed: (){
                        setState(() {
                          _count--;
                        });
                      },
                      child: const Text(
                        "Down"
                      ),
                  ),
                  OutlinedButton(
                    onPressed: (){
                      setState(() {
                        _count = 0;
                      });
                    },
                    child: const Text(
                        "Reset"
                    ),
                  ),
                  OutlinedButton(
                    onPressed: (){
                      setState(() {
                        _count++;
                      });
                    },
                    child: const Text(
                        "Up"
                    ), //Text
                  ), //OutlinedButton
                ],
              ), //Row
            ],
          ), //Column
        ), //Center
      ), //Scaffold
    ); //MaterialApp
  }

}

지금부터 하나하나 뜯어보도록 하자.

 

1. StatefulWidget

class CounterPage extends StatefulWidget{
  CounterPage({Key? key}): super(key: key);

  @override
  State<CounterPage> createState()=> _CounterPageState();

}

StatefulWidget을 상속 받는 CounterPage class를 생성한다.

 

CounterPage({Key? key})는 생성자이다.

super를 통해 StatefulWidget의 생성자를 불러온다.

 

2. State

그 다음으로는 StatefulWidget의 상태를 생성해준다.

createState()를 사용해 상태를 생성해준다. 

_CounterPageState 클래스가 이 상태를 상속받는다.

class _CounterPageState extends State<CounterPage> {

  int _count=0;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
    
    ...

_CounterPageState는 앞서 생성안 CounterPage의 상태를 상속받는다.

 

_count는 카운트한 값을 저장하는 용도이다.

 

Widget build 메서드는 StatelessWidget과 동일하다.

 

3. 화면 구성하기

@override
Widget build(BuildContext context) {
  return MaterialApp(
    home: Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Text(
              "$_count",
              style: const TextStyle(
                fontSize: 30.0
              ),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                OutlinedButton(
                    onPressed: (){
                      setState(() {
                        _count--;
                      });
                    },
                    child: const Text(
                      "Down"
                    ),
                ),
                OutlinedButton(
                  onPressed: (){
                    setState(() {
                      _count = 0;
                    });
                  },
                  child: const Text(
                      "Reset"
                  ),
                ),
                OutlinedButton(
                  onPressed: (){
                    setState(() {
                      _count++;
                    });
                  },
                  child: const Text(
                      "Up"
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    ),
  );
}

굉장히 코드가 길어 보이지만 텍스트 하나와 버튼 3개로 구성된 간단한 코드이다.

 

화면 구성을 위한 위젯 트리는 다음과 같다.

앱 위젯 트리
화면 위젯 트리 구조

우선 Center 위젯을 통해 모든 위젯이 중앙에 위치할 수 있도록 만든다. 

그 다음 Column을 통해 Text 위젯과 Row 위젯이 행 방향으로 정렬되도록 한다.

 

Row 안에는 down, up, reset 버튼이 열 방향으로 위치할 수 있도록 한다.

OutlinedButton(
  onPressed: (){
    setState(() {
      _count = 0;
    });
  },
  child: const Text(
      "Reset"
  ),
),

버튼 안의 onPressed 파라미터 안에 setState()가 들어가 있는 것을 볼 수 있다.

setState 안에 실행할 코드를 넣으면 버튼을 눌렀을 때 코드를 실행하고, 화면을 업데이트한다.

 

만약 안에 setState가 없으면 아무리 버튼을 눌러도 화면이 업데이트 되지 않는다.

반응형

'플러터 (flutter)' 카테고리의 다른 글

Flutter - 내비게이션 바 (NavigationBar)  (0) 2023.06.26
Flutter PageView 위젯  (0) 2023.06.24
Flutter WebView 위젯  (0) 2023.06.23
Flutter와 위젯(Widget) (2)  (0) 2023.06.23
Flutter와 위젯(Widget)  (0) 2023.06.21