본문 바로가기
비전공자를 위한 Flutter/앱 개발 강의보기

Flutter 첫 프로젝트 - my_app 코드 간단 설명 (1/2)

by 밍잔 2022. 4. 28.
*주의 : 이 강의는 비전공자의 이해를 돕기 위한 강의로 실제내용을 각색했음을 알립니다. 맛보기이니 외우려 하지 마시고 천천히 훑어보기만 하세요!

 

이제 본격적으로 플러터를 뜯어보도록 하죠. 윈도우 사용하시는 분들은 F5, 맥을 사용하시는 분들은 Fn+F5를 눌러서 처음 앱을 실행하고 나면 별거 없습니다. 오른쪽 아래에 있는 파란색 +버튼을 누르면 화면 중앙에 있는 숫자가 1씩 늘어나는 앱입니다.

 

 

여러분이 만든 my_app 폴더의 main.dart 파일에 있는 코드를 주석만 지워서 그대로 가져와 볼게요. main.dart에 있는 몇 줄 없는 코드만으로 이 앱이 실행된 거거든요.

 

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(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
       _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
         mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), 
    );
  }
}

 

자... 생각보다 몇 줄 안 돼죠?? 여러분이 이해하기 쉽게 최대한 한글로 바꿔볼게요. 

 

필요한파일을가져와요 '패키지:플러터/건축양식';

그냥실행해요 휴대폰이앱실행하기() {
  플러터가앱실행하기(변치않는 앱이란());
}

정의해요 앱이란 알고보니 생각이없는아이 {
  변치않는 앱이란({이름이있을까? 이름}) : 부모(이름: 부모의이름);

  @다시말할게요
  건물 건축(서사) {
    이 건물은 이거예요 = 건축양식(
      건물이름: '플러터 데모',
      건물테마: 색깔파레트(
        포인트색깔: 파란색,
      ),
      인테리어: 변치않는 내집(내집별명: '플러터 데모 홈페이지'),
    );
  }
}

정의해요 내집 알고보니 생각이있는아이 {
  변치않는 내집({이름이있을까? 이름, 꼭필요해요 집별명이}) : 부모(이름: 부모의이름);

  안바꿔요 문자 별명;

  @다시말할게요
  상태<내집> 상태를만들어요() => 나만보는내집상태();
}

정의해요 나만보는내집상태 알고보니 상태<내집> {
  소수점없는숫자 나만보는숫자 = 0;

  그냥실행해요 숫자를증가시켜요() {
    상태가어떻게바뀌니?(() {
       나만보는숫자를+1증가시켜요;
    });
  }

  @다시말할게요
  건물 건축(서사) {
    이 건물은 이거예요 = 스캐폴드건축양식(
      지붕: 지붕(
        제목: 글자(아까위에말한.안바꾼다고했던별명),
      ),
      건물내부: 모든걸가운데로모으기(
        건물내부: 건물을세로로쌓기(
         세로정렬은어디부터?: 세로정렬은.가운데로,
          안에세울건물들은: <건물만>[
            변치않는 글자(
              '여러분이 얼마나 이 버튼을 눌렀는지 보여줘요:',
            ),
            글자(
              '$나만보는숫자',
              스타일: 이건물테마의헤드라인4스타일로보여주세요,
            ),
          ],
        ),
      ),
      떠다니는초인종버튼: 떠다니는초인종버튼(
        누르면: 숫자를증가시켜요,
        버튼설명: '숫자증가',
        버튼내부: 변치않는 아이콘(아이콘들중에서.더하기모양),
      ),
    );
  }
}

 

사실 이렇게 한글로 바꿔놓고 보면 코딩이 별거 없습니다. 컴퓨터는 코드를 위에서부터 아래로 한 줄씩 해석합니다. 앱도 마찬가지죠. 여러분이 양옆으로 보면서 비교할 수 있게 보여드리면서 한 줄씩 알려드릴게요.

 

 

플러터가 화면에 여러가지를 표시하는 건 건물을 짓는 것과 같습니다. 1번째 줄에 있는 import는 건물을 짓는데에 필요한 재료들을 가져오기 위해 사용해요. 플러터는 material이라는 건축 양식을 사용하는데요. 그걸 가장 처음에 가져오게 한 겁니다. 건물 지으려고 막 공사 시작하려고 하는데 재료가 없으면 시작을 못하겠죠?

 

 

3번째 줄에 있는 void main()를 볼게요. 프로그래밍에는 함수라는 게 있어요. 어렵게 말하면 함수고 쉽게 말하면 심부름을 시키는 겁니다. 심부름에는 2가지 종류가 있는데요, 하나는 그냥 시키기만 하는 거고, 하나는 뭘 가져오게 시키는 거예요. void는 그냥 시키는 겁니다. 

뭘 가져오게 시킬 때에는 void가 들어갈 자리에 뭘 가져오게 할지 말하면 됩니다. 휴대폰에서 앱을 실행하면 무조건 main()이라는 심부름을 시키게 되어있어요. 이 main()이라는 심부름의 내용을 {} 괄호 안에 설명하는 거죠.

 

만약 {} 대신 ;가 써져 있으면 그 심부름을 실행하라는 의미에요. runApp이라고 플러터에게 앱을 실행시키는 심부름을 시키네요. 이 플러터는 어떤 앱을 실행시킬지 알아야 하는데, 변치 않는 내앱을 실행시키라고 시켰어요.그럼 내앱은 뭘까요?

 

 

class는 뭔가를 정의하는 거예요. '지금부터 말하는 게 내앱이다!!'라고 선언하는거죠. 앱을 실행하면 화면에 사각형도 있고, 글자도 있고, 버튼도 있는데요. 화면에 보여지는 것들을 위젯이라고 불러요. 앱을 만드는 건 레고 조각들로 건물을 짓고 꾸미는 거랑 비슷해요. 위젯을 하나의 레고 조각이자 건물로 보면 됩니다. 위젯에는 2가지 종류가 있습니다. 하나는 생각이 있는 위젯(StatefulWidget), 하나는 생각이 없는 위젯이죠(StatelessWidget). 그래서 생각이 없는 아이라고 표현했습니다. 왜 이렇게 나눌까요? 

 

두 가지 대화를 보겠습니다.

줄리엣 : 오늘 몇 시에 집 앞으로 올 건가요?
로미오 : 저녁 7시까지 가려고 했소.
줄리엣 : 그때는 들킬지도 몰라요. 저녁 9시는 어때요?
로미오 : 알겠소. 저녁 9시까지 가겠소.

줄리엣의 말에 로미오는 들키지 않기 위해 도착시간을 9시로 변경했죠. 다음 대화를 보시죠.

줄리엣 : 오늘 몇 시에 집 앞으로 올 건가요?
마리오 : 7시.
줄리엣 : 그때는 들킬지도 몰라요. 저녁 9시는 어때요?
마리오 : ...7시.
줄리엣 : 그때는 들킨다니까요? 저녁 9시에 와요.
마리오 : ......7시!
줄리엣 :

마리오는 줄리엣이 뭐라 말하든 7시를 고집합니다. 바뀌지가 않습니다. 위젯도 마찬가지로 생각을 바꾸는 아이와 생각을 바꿀 생각이 없는 아이 2가지가 있습니다. 생각을 바꾸지 않는 아이는 항상 고집부리는 상태 그대로입니다. 따라서 불필요하게 의사소통을 더 할 필요도 없는거죠. extends는 '알고 보니 ~를 타고났다' 라는 뜻입니다. 내 앱은 생각 없는 아이의 성질을 타고났다는 의미인거죠. 

(StatelessWidget의 매운맛을 보고 싶은 분은 오른쪽 링크를 누르세요. https://mingzan.tistory.com/258)

 

MyApp은 상태가 변하지 않는 위젯

 

const는 '변하지 않는다'는 의미입니다. 위젯인 내 앱은 계속 생각이 변치 않을 것이고 항상 그 자리에 있을 겁니다. 그래서 const를 앞에 붙여준거죠. 위젯에는 따로 이름을 지어줄 수 있습니다. key가 그 이름을 의미하죠. Key옆에 있는 물음표?는 이름이 있을 수도 있고 없을 수도 있다는 의미입니다. 이름이 없는 경우 부모의 이름을 그대로 따르게 되죠. 

 

 

@override는 '다시 말해서'라는 뜻이에요. 생각이 있는 위젯이든 없는 위젯이든 각자 위젯을 만드는 방식이 있어요. 근데 그걸 여러분이 다시 교육해주는 거예요. build라는 심부름을 다시 교육할 건데요. build는 위젯(건물)들을 모아서 새로운 건물로 만든다는 뜻이에요. 그래서 건축이라고 표현했죠. 아까 void 기억하시나요? 지금 보니까 void가 들어갈 자리에 Widget이 들어가 있어요. 여러분이 시킨대로 건축을 다 마치고 나면 새로운 건물이 하나 남겠죠? 그래서 건축 심부름을 마치면 그 건물을 하나 가져올 겁니다. 그 건물을 다시 가져오게 시키는 게 return이라는 겁니다. 심부름 내용인 {}안에 return을 시키면 그걸 다시 가져오게 한다는 의미죠.

 

 

build 심부름의 ()괄호 안에 BuildContext라는 게 있는데요. BuildContext는 '서사'입니다. 이 서사가 담긴 책 제목을 context라고 이름을 지은거죠. context에는 여러분이 그동안 이 건물을 어떻게 지어왔는지에 대한 서사가 담겨있어요. 예를 들면 처음에는 하얀색으로 건물을 짓다가, 갑자기 여러분의 생각이 바껴서 검은색으로 건물을 짓고 있다는 등의 정보가 들어있죠. 

 

 

플러터에게 build 심부름으로 서사가 적혀있는 책을 보여주고 MaterialApp를 가져오게 했는데요. MaterialApp은 뭔지 아래 링크를 눌러 다음 강의에서 알아보죠. 

 

https://mingzan.tistory.com/257

댓글