[FlutterBoot] Day00 - HelloFlutter

tamagoyakii·2023년 11월 27일
1

FlutterBoot

목록 보기
1/5
post-thumbnail

✨ 문제 풀이

✅ 기본 문제 - HelloFlutter

✨ TIL

이번 기본 문제는 Counter를 만드는 것이었다. 나는 플러터로 뭘 그려보는 게 처음인지라 처음 보는 것들이 많다! 하나씩 차근차근 살펴보자.

1. runApp

runApp() 함수는 받은 위젯을 팽창시켜 화면에 부착한다. 내부의 위젯이 전체 화면을 가득 채운다는 말이다. 때문에 내부 위젯에 정렬을 주고 싶다면 정렬 위젯을 사용하는 것이 좋다.

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

runApp을 다시 호출하면 이전의 루트 위젯이 화면에서 분리되고, 해당 위젯이 새로운 위치에 연결 된다. 리랜더링 된다는 뜻인 것 같다. 새 위젯과 기존의 위젯을 비교하여 바뀐 부분이 렌더 트리에 적용된다. 아래에서 배울 StatefulWidget이 랜더 트리를 새로 구성할 때와 비슷하다.

2. StatelessWidget

플러터의 위젯은 크게 두 가지로 구분된다. State가 있는 것과 없는 것이다. 그중 StatelessWidget은 말 그대로 상태가 없는 녀석이다. StatelessWidget은 변화하는 상태가 없기 때문에 한번 그려지고 나면 고정된 형태를 유지한다.

이 클래스는 보통 extends 키워드를 통해 상속을 해서 사용한다. 기본 형태는 다음과 같다.

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

  
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}

build() 함수는 화면에 위젯을 그려주는 함수다. 반드시 구현해야 하는 함수기 때문에 @override 키워드를 통해 새로운 build 함수를 정의해 주자.

3. StatefulWidget

StatefulWidget은 아무리 봐도 StatelessWidget과 반대되는 녀석일 것이다. 즉, 변경이 가능한 상태를 갖는 위젯이다. 플러터가 이야기하는 상태는 다음과 같다.

  1. 위젯이 빌드 될 때 동기적으로 읽을 수 있다.
  2. 위젯의 생명주기 동안 변경될 수 있다.

setState() 함수를 사용하여 상태를 바꾸면, 바뀐 데이터가 위젯에 새로 그려진다. StatelessWidget과 다르게 동적인 UI 구성이 필요할 때 사용된다.

StatefulWidget의 기본 형태는 다음과 같다.

class MyWidget extends StatefulWidget {
  const MyWidget({super.key});

  
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}

Counter를 만들어야 하기 때문에 StatefulWidget을 사용해 줬다.

class HelloFlutter extends StatefulWidget {
  const HelloFlutter({super.key});

  
  State<HelloFlutter> createState() => _HelloFlutterState();
}

class _HelloFlutterState extends State<HelloFlutter> {
  int score = 0;

  void increaseScore() {
    setState(() {
      score++;
    });
  }

  void decreaseScore() {
    setState(() {
      score--;
    });
  }

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('$score'),
        Row(
          children: [
            FilledButton(
                onPressed: increaseScore, child: const Icon(Icons.add)),
            FilledButton(
                onPressed: decreaseScore, child: const Icon(Icons.remove)),
          ],
        ),
      ],
    );
  }

위와 같이 score 변수를 선언해 주고, setState() 함수를 통해 score 값을 바꿔준다. 그러면 바뀐 상태에 따라 뷰가 업데이트되는 것을 확인할 수 있다.

4. Material vs. Cupertino

플러터는 네이티브 앱 프레임워크가 아니기 때문에 특정 플랫폼의 UI를 사용할 수 없다. 때문에 그들을 흉내 내는 패키지들이 많이 나온다.

Material과 Cupertino는 플러터에서 기본적으로 제공하는 디자인 패키지다. Material은 google, Cupertino는 iOS의 디자인 가이드를 따르는 UI 컴포넌트를 제공한다.

플러터 프로젝트를 처음 생성하면, 기본 설정은 Material 디자인을 따르도록 되어있다. 때문에 상단에 다음과 같은 import를 확인할 수 있다.

import 'package:flutter/material.dart';

Cupertino를 사용하고 싶다면 다음과 같이 import 하면 되겠다.

import 'package:flutter/cupertino.dart';

나는 기본 설정인 MaterialApp을 사용하기로 했다.

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

  
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HelloFlutter(),
    );
  }
}

사용 방법은 간단하다. 이렇게 MaterialApp 위젯을 호출하고, home에 원하는 위젯을 넣으면 된다.

플러터를 디버그 모드로 실행하면 위에 "DEBUG"라고 적힌 배너가 표시된다.

그렇다. 나는 저게 너무 거슬렸다. 위 코드의 debugShowCheckedModeBanner 옵션은 그 배너를 없애기 위한 것이다.

5. Scaffold

Material 디자인의 기본 레이아웃 구조다. 이런 친구들로 이루어져 있다.

  1. appBar
  2. body
  3. bottomNavigationBar
  4. bottomSheet
  5. drawer
  6. endDrawer
  7. floatingActionButton
  8. persistentFooterButtons

키보드가 나타나거나 할 때 다시 빌드 되며, body의 사이즈를 조정하여 키보드를 위한 공간을 마련해 준다.

6. Key

코드를 치다보니 이런 경고가 뜬다.

그게 뭔데...

키는 위젯을 식별하기 위해 사용된다. 플러터에는 세가지 트리가 있다. 각각 Widget, Element, RenderObject 트리다.

Widget 트리가 빌드되면, 그 뒤에 Element 트리가 생성된다고 한다. 이때 Widget 트리는 재구성될 때 아예 새로 만들어지지만, Element 트리는 기본적으로 재사용되고, 재구성된 Widget 트리를 참조하여 바뀐 부분만 새로 만들어진다. 이렇게 재구성된 위젯을 구분할 때 키가 사용된다. 더 자세한 내용은 공식 문서를 참고!

Key class 공식 문서

StatelessWidget이나 StatefulWidget을 만들 때 생성자에 key를 넣지 않으면 계속 경고를 준다. 부모에게 동일한 키를 전달해줘야 한다는 것이다. 때문에 생성자에 이렇게 추가해줘야 한다.

class MyWidget extends StatelessWidget {
  const MyWidget({super.key});	// 부모 위젯의 키 설정
  ...
}

7. Column & Row

css의 정렬과 비슷하다. Column은 세로 방향, Row는 가로 방향으로 정럴해준다. 보통 다음과 같은 형태다.

Column(
  crossAxisAlignment: CrossAxisAlignment.center,
  mainAxisAlignment: MainAxisAlignment.center,
  children: [...],
}

Row(
  crossAxisAlignment: CrossAxisAlignment.center,
  mainAxisAlignment: MainAxisAlignment.center,
  children: [...],
}

crossAxisAlignment, mainAxisAlignment 이 둘은 수평, 수직축을 기준으로 어떻게 정렬할 것인지를 정해준다. css의 justify-content, align-items와 비슷하다.

✨ Comment

코드를 칠 때는 구현하기 바빴는데, 블로그에 기록을 남기려니까 글을 쓰기 위해 더 자세히 찾아보게 된다. 진짜 시작은 내일부터지만... 화이팅이닷! 아자잣~!

참고

https://api.flutter.dev/flutter/widgets/runApp.html
https://api.flutter.dev/flutter/widgets/StatelessWidget-class.html
https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html
https://api.flutter.dev/flutter/material/Scaffold-class.html
https://nsinc.tistory.com/214

0개의 댓글