android 개발/android 이론(flutter)

Flutter Widget 알아보기

웅드 2023. 5. 16. 12:37

Flutter의 모든 위젯은 2가지로 나뉠 수 있다

 

  • StatelessWidget : 상태 변화가 없어 화면을 새로 고침할 필요가 없는 위젯
  • StatefulWidget : 상태 변화가 있어 화면을 새로 고침할 필요가 있는 위젯

이렇게 말로 설명한 것만 보면 StatelessWidget는 변화가 없는 정적인 화면을 의미하고,

StatefulWidget은 변화가 있는 동적인 화면을 의미한다는 것을 알 수 있다.

 

1. StatelessWidget

  • 화면의 내용이 변하지 않는 위젯

import 'package:flutter/material.dart';

void main() {
  print("시작");
  runApp(const MyApp());
}

// StatelessWidget을 상속
class MyApp extends StatelessWidget {
  // 생성자
  const MyApp({Key? key}) : super(key: key);
  
  // build 라는 이름의 메서드(함수) 실행
  @override
  Widget build(BuildContext context) {
    print("build 호출");
    
    return const MaterialApp(
      home: Scaffold(
        body: Center(
          child: Text(
            "hello Stateless Widget",
            style: TextStyle(fontSize: 35),
          ),
        ),
      ),
    );
  }
}
  • extends StatelessWidget : StatelessWidget의 기능을 물려 받는다.
  • 생성자 : 클래스 이름과 동일한 함수
  • build 함수 : 화면에 보여줄 자식 위젯을 반환한다.

9번째 줄에 MyApp 클래스가 직접 만든 StatelessWidget 위젯이다.

 

※ 화면에 보이는 첫번째 위젯은 일반적으로 MaterialApp 또는 CupertinoApp 위젯으로 시작한다.


2.StatefulWidget

  • 기본적으로 2개의 클래스로 구성되어 있다.

  • MyApp : StatefulWidget의 기능을 물려받은 클래스
  • _MyAppState : MyApp 상태를 가진 클래스 ( 실질적인 내용은 여기에 들어간다)
  • 화면을 그리는 build함수는 상태 클래스(_MyAppState)에 있다.
// ignore_for_file: prefer_const_constructors
import 'package:flutter/material.dart';

void main() {
  print("시작");
  runApp(const MyApp());
}

// StatefulWidget을 상속
class MyApp extends StatefulWidget {
  // 생성자
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

// MyApp의 상태(State)를 나타내는 클래스
class _MyAppState extends State<MyApp> {
  int number = 1; // number가 1인 상태

  @override
  Widget build(BuildContext context) {
    print("build 호출");

    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Text("$number", style: TextStyle(fontSize: 35)), // 변수를 문자열에 넣는 방법
        ),
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.add),
          onPressed: () {
            print("클릭");

            // setState : build 메서드(함수)를 다시 호출해서 화면 갱신
            setState(() {
              number += 1; // number를 1만큼 증가
            });
          },
        ),
      ),
    );
  }
}

 

파랑색 + 버튼 클릭시 실행 순서

  1. 34번째 줄 print("클릭 됨"); 가 출력된다.
  2. 38번째 줄 number 1이 증가된다.
  3. 37번째 줄의 setState로 인해 화면이 갱신된다 -> build 함수 호출
  4. build 함수가 호출되어 24번째 print("build 호출") 가 출력된다.

 

 

 

★ 정적인 화면과 동적인 화면에 대해서 알아보았다. 이제 화면들 사이를 오갈 수 있는 함수를 알아보자!


3. Navigation (화면이동)

 

Flutter에선 각 화면을 라우트(Route)라고 부르며, 화면을 이동할 때 네비게이터(Navigator)를 사용한다.

 

  • 다음 페이지로 이동하기
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SecondPage()), //이동하려는 페이지
);

 

  • 현재 화면 종료
Navigator.pop(context); // 종료

 

 

// ignore_for_file: prefer_const_constructors

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: FirstPage(),
    );
  }
}

// 첫 번째 페이지
class FirstPage extends StatelessWidget {
  const FirstPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("홈"),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text("다음 페이지로 이동"),
          onPressed: () {
            // 페이지 이동
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => SecondPage()),
            );
          },
        ),
      ),
    );
  }
}

// 두 번째 페이지
class SecondPage extends StatelessWidget {
  const SecondPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("두 번째 페이지 입니다!"),
      ),
      backgroundColor: Colors.amber,
      body: Center(
        child: ElevatedButton(
          child: Text("첫 번째 페이지로 되돌아가기"),
          onPressed: () {
            // 뒤로가기
            Navigator.pop(context);
          },
        ),
      ),
    );
  }
}

 

★ 화면이 많아지는 경우, Named Route 방식을 사용하기도 한다.

반응형