본문으로 이동

플러터:변하는 화면(StatefulWidget): 두 판 사이의 차이

학교의 모든 지식. SMwiki
잔글편집 요약 없음
잔글 개요
2번째 줄: 2번째 줄:


== 개요 ==
== 개요 ==
화면 변화 반영하기.
어플은 정적인 화면만으로 구성되진 않는다. 화면을 구성하는 요소에 변화를 주어야 하는데, 이때 상태(state)를 어떻게 관리하고 화면에 반영하는지가 매우 중요하다.
어플은 정적인 화면만으로 구성되진 않는다. 화면을 구성하는 요소에 변화를 주어야 하는데, 이때 상태(state)를 어떻게 관리하고 화면에 반영하는지가 매우 중요하다.
----
= 기본 카운터 앱 전체 코드 =
= 기본 카운터 앱 전체 코드 =
<syntaxhighlight lang="dart">
아래는 기본적으로 많이 제공되는 예시인 기본 카운터 앱이다.<syntaxhighlight lang="dart">
import 'package:flutter/material.dart';  
import 'package:flutter/material.dart';  



2025년 12월 15일 (월) 08:43 판

틀:플러터 Dart:개요 플러터에 대한 지식 분류

  1. 플러터:개요
    1. 플러터:VSCode
    2. 플러터:안드로이드 스튜디오
  2. 플러터:실행
  3. 플러터:개념 잡기
    1. 플러터:화면 하나 만들기
    2. 플러터:변하는 화면(StatefulWidget)
    3. 플러터:화면 전환(화면 쌓기, 하단 네비게이션 바)
    4. 플러터:화면 전환(Drawer)
    5. 플러터:입력 관련
      1. 플러터:버튼
      2. 플러터:키보드 입력
      3. 플러터:슬라이더
    6. 플러터:그래프 그리기(fl chart)
    7. 플러터:데이터 저장(간단한 데이터)
    8. 플러터:인증(Firebase 인증)(미완)
    9. 플러터:인증(OAuth2)(미완)
  4. 권한 사용
    1. 플러터:마이크 입력
  5. 위젯
    1. 플러터:아이콘
    2. 플러터:레이아웃 계열 위젯
    3. 플러터:네비게이션 계열 위젯
    4. 플러터:버튼
    5. 플러터:상태관리(미완)
  6. 플러터:DB연결
    1. 플러터:Firebase(미완)
    2. 플러터:MySQL(미완)
  7. 디자인
    1. 플러터:테마
    2. 플러터:앱바
  8. 플러터:배포
    1. 플러터:배포(안드로이드)(미완)
  9. 플러터:참고자료
  10. 플러터:위젯
    1. 플러터:공간배치용 위젯
  11. 플러터:구글 AdMob(미완)
  12. 플러터:라이브러리
    1. 플러터:logger

개요

화면 변화 반영하기.

어플은 정적인 화면만으로 구성되진 않는다. 화면을 구성하는 요소에 변화를 주어야 하는데, 이때 상태(state)를 어떻게 관리하고 화면에 반영하는지가 매우 중요하다.

기본 카운터 앱 전체 코드

아래는 기본적으로 많이 제공되는 예시인 기본 카운터 앱이다.

import 'package:flutter/material.dart'; 

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',              // 앱 이름
      debugShowCheckedModeBanner: false,  // 오른쪽 상단의 "debug" 띠 제거
      theme: ThemeData(
        colorSchemeSeed: Colors.blue,     // 전체적인 색상 팔레트 지정
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),  // 첫 화면
    );
  }
}

class MyHomePage extends StatefulWidget {
  // StatefulWidget = 상태(state)를 가지고 변경 가능한 화면을 만들 때 사용
  final String title; // 화면 상단 AppBar에 표시할 제목

  const MyHomePage({super.key, required this.title});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
  // 이 위젯이 사용할 State 객체 생성
}

class _MyHomePageState extends State<MyHomePage> {
  // 실제로 상태를 가지고 동작하는 부분은 여기(State 클래스)

  int _counter = 0; // 화면에 표시될 숫자 상태 값 (초기값 = 0)

  void _incrementCounter() {
    // FloatingActionButton을 눌렀을 때 실행되는 함수
    setState(() {
      // setState()를 호출해야 화면을 다시 그리게(Rebuild) 된다. 이 함수 동작이 끝나면 이 상태를 다시 그림.
      _counter++; // 상태 값 증가
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
        // widget.title → 부모(StatefulWidget)에서 받은 title 값
      ),

      body: Center(  // Center = 가운데로 정렬
        child: Column(  // Column = 세로로 위젯을 쌓는 레이아웃
          mainAxisAlignment: MainAxisAlignment.center, // mainAxisAlignment.center → 세로 가운데 정렬
          children: [
            const Text('You have pushed the button this many times:'),
            // 설명 문장 (고정 텍스트이므로 const 사용)
            Text(
              '$_counter', // 화면에 상태 값 표시
              style: Theme.of(context).textTheme.headlineMedium,  // 앱 테마에서 지정된 큰 글씨 스타일 사용
            ),
          ],
        ),
      ),

      floatingActionButton: FloatingActionButton(  // 오른쪽 아래 떠있는 버튼 (FAB)
        onPressed: _incrementCounter, // 버튼 클릭 → 상태에 정의된 함수 실행
        tooltip: 'Increment',         // 버튼 길게 누르면 뜨는 설명
        child: const Icon(Icons.add), // + 아이콘
      ),
    );
  }
}

이해를 위한 추가 설명

요소 설명 비고
StatefulWidget “상태를 가질 수 있는 위젯”. UI 틀(설계도) 역할 이를 상속한 클래스는 State를 작성해야 한다.
class MyHomePage extends StatefulWidget {
  // StatefulWidget = 상태(state)를 가지고 변경 가능한 화면을 만들 때 사용
  final String title; // 화면 상단 AppBar에 표시할 제목

  const MyHomePage({super.key, required this.title});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
  // 이 위젯이 사용할 State 객체 생성
createState를 오버라이딩하는데, 타입은 State인데, 또 State 타입은 MyHomePage이고,

createState의 반환은 _MyHomePageState 타입이다.

_MyHomePageState 객체를 반환하여 Flutter가 화면 상태 관리(State)를 연결하도록. 결과적으로 새로운 State가 생성된다.

State
class _MyHomePageState extends State<MyHomePage> {
  // 실제로 상태를 가지고 동작하는 부분은 여기(State 클래스)
  • State를 상속받는데, MyHomePage를 타입으로 한 State를 상속받는다.
  • State 안에서는 부모 StatefulWidget의 프로퍼티를 widget으로 접근한다.
setState()
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }
setState는 함수를 인자로 받는 함수이며, () {} 는 익명함수의 구조이다.

State를 상속받은 클래스에서 setState()을 사용하면, 이 함수의 동작이 끝날 때 해당 클래스에 대한 것들을 새로 그린다.

setState가 하는 일(핵심 원리)

  1. _counter를 변경.
  2. 해당 State의 build() 함수를 다시 호출.
  3. 화면(UI)이 새 값을 반영해 다시 그려짐.

의문

State<MyHomePage> 대신 그냥 State로 쓰면 안되나?

상속이나 오버라이딩에서 자연스레 생기는 의문인데, State와 위젯을 안전하게 연결하기 위해선 위처럼 써야 한다. 그냥 State를 쓰면 일반 State와 연결되어 상위 위젯의 값을 사용할 수 없다.