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

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

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

 

이어서 MaterialApp에 대해 알아보죠. 지난 시간에 Material이 건축양식이라고 말씀드렸죠? MaterialApp은 그 양식에 맞춰 만든 앱이라는 뜻이 됩니다. 이 양식에 따르면 몇 가지 필요로 하는 정보가 있어요. 예를 들면 건물 이름이, 건물 테마, 인테리어죠.

 

 

MaterialApp의 괄호 안에 title이라고 적혀 있는 게 바로 (건물 이름 = 프로젝트 이름)인데요. 어디 다른데에 노출되는 정보는 아닙니다. 그저 여러분의 앱 이름이 무엇인지 적어놓을 뿐이에요. 그 다음에 theme이라고 적힌 게 바로 (건물 테마 = 앱의 테마)입니다. 앱 전체에 사용될 컬러들을 미리 저장해두고 갖다 쓰는거죠. 여러분이 미술 수업을 위해 파레트에 미리 짜놓아서 굳은 물감들 처럼요! 

 

 

 

앱은 벽이 유리로 된 투명한 건물입니다. 그래서 건물 내부의 인테리어가 훤히 보이죠. 여러분이 플러터로 코딩을 한다는 건 이 건물 안에 레고 조각(위젯)들로 인테리어 작업을 한다고 보시면 됩니다. 예제에 쓰인 MyHomePage는 여러분의 집이구요. 여러분 집에 title(이름)이 필요하다고 하는데요, 왜 title을 필요로 하는지 알아볼까요?

 

내용이 가로로 길어서 사진이 좀 작네요 ㅠㅠ 확대해서 봐주세요

 

내 집 MyHomePage가 알고 보니 생각이 있는 아이(StatefulWidget)였다고 하네요! 생각 없는 아이(StatelessWidget)랑 비슷하게 생겼어요. (StatefulWidget의 매운맛을 보려면 오른쪽 링크를 누르세요. https://mingzan.tistory.com/259)

 

1. const MyHompage = 영원히 바뀌지 않을 내 집이고.

2. Key? key = 이 집에 이름이 있나?

3. : super(key: key) 없으면, 부모님 이름을 그대로 쓰겠다.

 

근데 자세히 보니까 다른 점이 몇 군데 있죠?

 

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

갑자기 , required this.title 가 생겼다.

이 생각 있는 아이는 이 집의 이름이 뭔지 반드시 알아야겠대요. 이유는 모르겠지만 반드시 알아야겠다 싶을땐 required를 써요. 해석하면 (this.title = 이 집의 이름이 필요하다), (required this.title = 이 집의 이름이 반드시 필요하다)는 얘기죠.

 

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

final String title;


갑자기 final String title; 가 생겼다.

 

title(이름)이 반드시 필요한데, 한 번 알려주면 끝까지 그렇게 알고 있겠대요. 끝까지 그렇게 알고 있겠다고 할 때 final을 써요. 이름을 숫자로 지을 사람은 별로 없으니 당연히 문자겠죠? String은 문자를 의미해요. 위에서 저렇게 꼭 required로 알고 싶다고 했을 땐, 의견을 덧붙이지 않고 끝까지 그 문자 그대로 알고 있겠다고 말해주는 거예요. final 끝까지 알고 있겠다. String 문자인 title 집이름을;

{} 괄호처럼 심부름 내용을 설명하는 게 아니라면 ;을 쓰는데요. ;는 선언한다는 뜻입니다.

 

 

언제 뭘 써야할지 헷갈리셔도 괜찮아요. Visual Studio Code에서 다 알려주거든요! 아래는 ;를 써야하는데 ;가 안 쓰여있을 때 저렇게 알려줍니다. 저런 메시지를 보면 코드 마지막에 ;를 써주세요.

 

 

아래는 {}로 심부름 내용이 쓰여야 하는데 아무것도 안 써져 있을 때 저렇게 알려주죠. 저런 메시지를 보면 괄호를 열고 { 여기에 심부름 내용을 쓰시고 } 괄호를 닫아주세요.

 

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

뭔지 모르겠는게 하나 생겼는데요. 이 코드를 해석하자면 생각을 새로 만들어주는 겁니다. 왜 새로 만들어줘야 할까요? 여러분이 누군가를 설득할 때 그 사람의 생각만 바꾸면 되지, 그 사람의 유전자부터 하나씩 뜯어서 새로운 사람을 만들 필요는 없기 때문이에요. State는 생각 또는 상태라고 생각하시면 됩니다. 생김새는 생각 없는 아이와 같지만 생각을 만들어주는 걸 이 코드로 하는거죠. _MyHomePageState라는 게 또 새로 생겼는데 이건 뭔지 알아볼까요?

 

 

여기도 글씨가 작네요.. 확대해서 봐주세요!

 

MyHomePage의 생각과 생김새가 써진 코드입니다.

int _counter = 0;

이 아이는 숫자를 세고 있어요. _counter라는 게 숫자 몇 인지 세고 있죠. 0부터 시작하고 있네요. 그외에 다른 걸 생각하고 있지는 않고 있습니다. 생각하는 것들은 보통 build 심부름 위에 써져 있거든요.

 

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

여러분이 알고 있는 심부름이 등장했네요! build위에 써져 있으니까 이 심부름을 할 생각을 하고 있는 거예요. void니까 그냥 시키는 건데요. 심부름 이름을 보니까 카운터를 증가시키라네요. 괄호 안의 내용을 볼까요?

 

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

setState라는 심부름을 다시 시키는데요. setState는 이 아이가 생각을 다시 바꾸는 거예요. 더하기가 2개 이어져있는 ++는 1 더하기와 같은 말이에요. (_counter = _counter + 1;) 이거랑 같은 의미죠. 이 심부름을 한 번 하면 아까 0이었으니까 1을 더해서 1이 되겠네요. 심부름을 한 번 더하면 2가 되겠죠!

 

 

아까 나왔던 (build = 건물을 만드는 심부름)이 나왔네요. 이 아이의 겉모습은 여기에 써있는 재료대로 생겼을 거예요. 하나씩 살펴보죠.

@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),
      ),
    );
  }

 

Scaffold부터 살펴보죠. Scaffold가 심부름 결과로 다시 가져와지는 걸 보니 Scaffold는 위젯(건물)인가 봅니다. 이 건물은 3가지로 구성되어 있는데요. 지붕(appBar), 건물 내부(body), 초인종(floatingActionButton) 이렇게 3가지네요.

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(),
      floatingActionButton: FloatingActionButton(),
    );
  }

 

appBar 지붕부터 살펴보죠. AppBar라는 레고 조각을 이용해서 지붕을 만들었는데요. 이 지붕에는 건물 이름을 쓸 모양인가 봅니다. 이름(title)을 필요로 하고 있어요. 이 이름에는 문자를 바로 쓰지 않고 Text라는 간판 위젯이 필요하네요. 지붕에 그냥 글씨를 쓸 수는 없겠죠. 

appBar: AppBar(
  title: Text(widget.title),
),

 

간판 안에는 widget.title이라고 쓰여있는데요. 아까 이 아이가 꼭 필요하다고 했던 이름 기억나세요?

final String title;

아까 물어봤던 이 이름을 쓰는데요. 이건 이 아이가 스스로 생각하고 있던게 아니라 물어봐서 안 거였죠? 물어봐서 안 것들은 앞에 widget. 을 붙여줘야 해요. 아까 알게 된 Flutter Demo Home Page가 지붕에 써있죠? 

 

 

다음은 지붕 아래의 건물 내부의 모습인데요. 뭐가 많죠? 하나씩 볼게요.

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,
      ),
    ],
  ),
),

 

이 Center라는 위젯은 모든 위젯들을 가운데로 모아주는 역할을 해요. 무중력상태로 말이죠. 플러터에서는 그런 일이 가능하답니다! 

대부분 위젯들은 child라는 걸 필요로 합니다. 레고 조각을 보시면 하나의 레고 조각을 가지고 완성품이라고 하지 않죠? 부품과 부품들을 연결해서 하나의 자동차가 완성되는 것과 같습니다. 이 Center라는 위젯 안에 또 인테리어를 할 위젯을 필요로 하죠. 그걸 자식 위젯(child)이라고 부릅니다.

Center(
  child: Column()
)

 

이 Column이라는 위젯은 젠가처럼 위젯들을 세로로 쌓아주는 역할을 해요. 웃긴 건 위에서부터 쌓을 수 있다는 점이죠.

Column(
  mainAxisAlignment: MainAxisAlignment.center,
  children: <Widget>[
    const Text(
      'You have pushed the button this many times:',
    ),
    Text(
      '$_counter',
      style: Theme.of(context).textTheme.headline4,
    ),
  ],
),

 

 

 

글자가 위에 써진 순서 그대로 위에서 아래로 쌓이고 있죠? 

mainAxisAlignment: MainAxisAlignment.center,

이 말은 위젯들을 세로로 쌓을 건데 풍선처럼 지붕에 붙어 있게 쌓을 건지, 무중력상태로 가운데에 쌓을 건지, 중력 있게 바닥에 쌓을 건지 정하는 거예요. 이 집에서는 무중력처럼 가운데에 쌓게 했네요. 그래서 화면 한 가운데에 문자들이 있는 거랍니다!

 

 

여러개의 위젯을 쌓을 땐 children이라는 표현을 쓰는데요. 이 [] 괄호 안에 있는 게 바로 자식 위젯들입니다. Text 위젯 2개가 자식 위젯이 되는거고, Column 위젯은 이 Text위젯 2개의 부모 위젯이 되는 거죠. 이 자식 위젯 2개가 서로 다른 점이 있습니다.

Column(
  children: <Widget>[
    const Text(
      'You have pushed the button this many times:',
    ),
    Text(
      '$_counter',
      style: Theme.of(context).textTheme.headline4,
    ),
  ],
)

 

하나는 절대 변하지 않는 문자가 쓰여 있습니다. 초인종을 몇 번 눌렀는지 알려주는 안내판 글자인데요. 이 안내판 글자를 굳이 바꿀 필요는 없겠죠. 그래서 영원히 변하지 않는다는 const가 쓰여 있습니다.

const Text(
  'You have pushed the button this many times:',
),

 

근데 다른 하나는 변하는게 있습니다. 바로 $_counter죠. 아까 아이가 0으로 생각하고 있던 그 _counter가 여기 써있습니다. 앞에 $가 붙어있는 이유는 숫자를 문자로 바꿔줄 때는 $돈을 주고 바꿔야합니다. 돈을 주면 숫자가 알아서 문자로 바뀌게끔 일하죠. 그 외에 style은 문자 스타일을 건물 테마에서 정해뒀던 헤드라인4 스타일로 바꾸라는 의미입니다. 사진을 다시 보면 $_counter는 숫자가 변하고, 글자 크기도 더 큰게 보이죠? 두번째 위젯은 숫자가 변하기 때문에 const를 사용할 수 없던 겁니다.

Text(
  '$_counter',
  style: Theme.of(context).textTheme.headline4,
),

 

마지막으로 초인종을 살펴보죠. 초인종은 오른쪽 아래에 파란색 동그라미입니다. FloatingActionButton이라는 위젯으로 만들죠. 이 위젯도 3가지 필요로 하는게 있네요.

floatingActionButton: FloatingActionButton(
  onPressed: _incrementCounter,
  tooltip: 'Increment',
  child: const Icon(Icons.add),
),

 

onPressed는 초인종을 누르면 뭘 할 건지 정해달라는 겁니다. _incrementCounter는 아까 이 아이가 숫자를 하나씩 더하려고 한다고 했었죠? 이 초인종을 누르면 아이는 숫자를 하나씩 더할겁니다. 실제로 사진을 보면 버튼을 누를때마다 화면 가운데에 있는 숫자가 1씩 늘어나죠. 

 

tooltip은 이 초인종이 뭔지, 무슨 버튼인지 알려주는 레이블이라고 보면 됩니다. 버튼에 +라고만 쓰여 있다보니 모를 수도 있거든요.

 

child는 아시다시피 자식 위젯입니다. const가 쓰여 있는걸 보니 절대 변하지 않는 조각인가 보군요. Icon은 아이콘을 보여주는 위젯입니다. Icons는 아이콘들을 모아둔 바구니죠. 이 바구니 안에서 add라는 더하기 모양의 아이콘을 골라서 보여주기로 되어있네요. 

 


 

여러분이 앞으로 앱을 만드는 건 이 정도만 해석할 줄 알면 대부분 만들 수 있습니다. 이걸 오늘 다 외울 필요는 없어요. 시간이 날 때 천천히 다시 훑어보는 정도면 됩니다. 이번 강의 포스팅은 앱 코딩은 이 정도면 된다라는 걸 보여드리려고 했던 거였죠. 다음 강의부터는 실제로 코딩을 실습해보겠습니다. 아래 링크를 눌러 여러분만의 앱을 만들어보죠.

댓글