[Flutter] main.dart 분석하기

저우웅·2025년 9월 27일

Flutter

목록 보기
1/8

오랜만에 블로그를 씁니다...

앱 개발에 도전하고픈 의지가 생겨 제가 운영중인 동아리의 앱 파트 코어 멤버로 활동하고 있습니다.

앱 파트 멤버 중 학교 수업에서 코틀린을 사용중인 학생들이 많았으나, 크로스 플랫폼 프레임워크를 사용하는 것이 좋겠다고 판단했습니다.

그 이후의 고민은 Flutter와 React Native중 어떤 프레임워크로 세션을 진행할지에 대한 것이었고, 결국 Flutter에 다같이 처음으로(!) 도전하기로 했습니다.

오늘은 첫 세션 주제였던 main.dart 분석에 대한 포스팅을 해볼까 합니다.



Flutter vs React Native 간단 소개


Flutter

  • UI가 OS에 관계 없이 어디서나 똑같이 보이도록 하기 위해 설계됨
  • 언어 - JIT(개발중), AOT(배포) 컴파일 둘 다 지원 \rarr 개발시에는 빠른 수정, 배포할 때는 빠른 실행 가능
  • UI 렌더링 - 자체 엔진(Skia)을 사용해서 직접 그림(무겁다), ios/android 상관 없이 같은 UI 보여줄 수 있음

React Native

  • 웹 개발 경험자를 위해 만들어짐. JS로 UI를 컨트롤 하는 방식 사용.
  • 언어 - JS엔진(Hermes, V8...)이 번역기 역할을 해줘야 함 -> 실행할 떄마다 해석해서 네이티브에 전달
  • UI 렌더링 - 운영체제 위젯을 가져다가 씀(가벼움), 커스터마이징 한계 O

추가적인 차이점은 다른 포스트에서 정리해보도록 하겠습니다.



1. import

import 'package:flutter/material.dart';
  • 디자인 시스템인 Material Design을 import 하는 코드

Scaffold(
    appBar: AppBar(title: Text("Hello")),
    body: Center(child: Text("Hi Flutter")),
) 
// 여기서 보이는 Scaffold, appBar, Text 같은 것들이 다 Material Design에 들어있는 위젯들
// Material Design을 import 하지 않으면 이런 위젯들을 사용할 수 없음!


2.void main()

void main() {
  // runApp: 루트 위젯을 화면에 붙여주는 역할
  runApp(const MyApp());
}
  • 프로그램의 진입접(entry point)

  • runApp: 전달된 위젯(위에서는 MyApp)을 루트로 하여 화면을 그릴 것임

    • 플러터 앱은 위젯으로 이루어진 트리 구조

    • runApp은 위젯만 받을 수 있음. (Text 등도 가능은 하나 방향성이 없어 오류 발생 가능성 O)

  • const MyApp: runApp에 전달된 위젯(= 이 프로젝트의 루트 위젯)

    • const를 붙였을까?

      • rebuild할 때마다 객체를 새로 생성하지 않음 \rarr 성능상 이점
      • const는 위젯이 불변(immutable) 일 경우에 사용. 화면 값이 바뀌는 위젯 (=Stateful Widget 등) 에는 사용 못 함

      = 이 위젯은 변하지 않으니 rebuild할 때 새로 만들지 말고 재사용해! 하고 알려주는 표시




3. MyApp (Stateless Widget)

// MyApp = 우리가 만든 앱을 감싸고 있는 위젯 = 루트 위젯
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    // 루트 위젯에서는 보통 MaterialApp을 리턴
    // Material App =
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const MyHomePage(title: '나의 첫 Flutter 페이지'), // 앱이 켜지면 가장 먼저 보여지는 부분
    );
  }
}

  • MyApp (루트 위젯)
    • StatelessWidget을 상속받음 \rarr 상태가 없는(= 내부 데이터 변화가 없는) 위젯
    • super.key: 위젯을 식별하는 값을 부모에게 전달
    • build(): 위젯이 화면에서 어떻게 보일지 flutter에게 알려주는 함수
      \rarr 루트 위젯에서는 보통 Material App을 리턴, title/theme/home 등의 앱 공통 설정을 정의



4. MyHomePage (Stateful Widget)

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
  // _MyHomePageState에서 실제 로직 + 상태 관리
}

  • StatefulWidget을 상속받음 \rarr 상태를 가질 수 있음

    • 상태가 있다 = 화면과 interaction했을 때 값이 바뀌고, 그 값에 따라 화면이 다시 그려진다
  • createState(): Stateful Widget은 상태를 관리할 객체(State)가 필요. 따라서 Stateful Widget을 만들 때는 반드시 createState을 구현해야 한다.




5. _MyHomePageState (State)

class _MyHomePageState extends State<MyHomePage>
  • 실제 상태 관리와 UI 그리기는 State에서 이루어진다.

  int _counter = 0; // _를 붙이면 private
  
    void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  void _resetCounter() {
    setState(() {
      _counter = 0;
    });
  }

  • 이런 변수와 함수들이 state
  • 상태가 바뀌면 build()가 다시 실행되어 UI가 갱신됨.
  • ! 함수에서 상태가 바뀌는 부분을 setState() 안에서 변경해야 화면이 갱신됨

  @override
  Widget build(BuildContext context) {
    return Scaffold(
    ...
    )
  }
  • _MyHomePageState.build() \rarr MyHomePage의 UI를 리턴
  • 실제 화면 안의 요소들로 구성됨

// 다소 수정된 코드
return Scaffold(
  appBar: AppBar(
    backgroundColor: Colors.green,
    title: Text(widget.title), // MyHomePage에서 넘어온 String
  ),
  body: Center(
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        const Text('버튼을 몇 번 눌렀을까용'),
        Text(
          _counter == 0
              ? '버튼을 눌러보세요!'
              : _counter < 5
              ? '조금만 더 눌러보세요!'
              : '버튼을 많이 누르셨군요!',
          style: Theme.of(context).textTheme.headlineMedium,
        ),
        const SizedBox(height: 20),
        ElevatedButton(
          onPressed: _resetCounter,
          child: const Text('카운터 초기화'),
        ),
      ],
    ),
  ),
  floatingActionButton: FloatingActionButton(
    onPressed: _incrementCounter,
    tooltip: 'Increment',
    child: const Icon(Icons.favorite),
  ),
);
  • Scaffold

    • Flutter에서 화면의 기본 뼈대

    • AppBar, body, FloatingActionButton 같은 기본 영역 제공

    • AppBar(상단바), body, FloatingActionButton등의 UI 구성요소가 들어있음



이렇게 main.dart의 구성을 간단히 알아보았습니다.

정리

  1. Flutter 앱 = 위젯 트리, 모든 UI 요소는 위젯으로 구성
  2. 상태를 가진 위젯(Stateful Widget)이 동적으로 UI를 갱신
  3. build() 함수가 각 위젯의 화면 설계도를 제공

다음 포스트에서는 UI의 렌더링 과정에 대해서 알아보겠습니다.

profile
ㅠㅠ

14개의 댓글

comment-user-thumbnail
2025년 9월 27일

개인적으로 애정하는 프레임워크가 Flutter인데 이렇게 다시 기초부터 차근차근 보니 또 새롭게 다가오는 것 같습니다. 또한 다른 크로스 플랫폼을 탐색할 때 생각났던 선택지가 KMM이었는데, React Native와 비교해보며 선택지의 폭을 늘리고 각 도구의 특징에 대해 다시 한번 생각해보는 기회가 되었습니다!

1개의 답글
comment-user-thumbnail
2025년 9월 27일

최근에 react 공부를 시작했는데 처음보는 자바스크립트 문법에 머리가 아득해지고 있습니다.
flutter는 또 새로운 문법으로 제 머리를 아득해지게 하네요.
새롭고 어려운거 도전하시면서 코어로까지 활동하시니 정말 멋지십니다!

1개의 답글
comment-user-thumbnail
2025년 9월 28일

플러터를 이해하려면 무엇보다 위젯과 state라는 개념의 이해가 중요해보이네요! 플러터만의 개성이 돋보이는 특징인것 같습니다.

1개의 답글
comment-user-thumbnail
2025년 9월 28일

최근 프로젝트 같이 하는 팀원이 플러터를 공부한대서
저도 배워보고 싶던 찰나에 너무 좋은 글이에요! 다음글도 기다릴게요ㅎㅎ

1개의 답글
comment-user-thumbnail
2025년 9월 29일

최근데 IOS에 관심이 생겨서 공부하고 있는데 재밌는 포스트 잘 읽고 갑니다 :)

1개의 답글
comment-user-thumbnail
2025년 9월 29일

이해가 잘됩니당

1개의 답글
comment-user-thumbnail
2025년 9월 30일

사실 앱과 관련한 거는 코틀린이라는 언어 하나뿐이었는데, 이렇게 플러터라는 새로운 프레임워크에 대해 알아가서 좋았습니다!! 플러터가 코틀린보다 유용하네여 ios도 가능하고 ㅎㅎ

1개의 답글