1. 플러터 : 텍스트

안드로이드 스튜디오에서 플러터 프로젝트를 만든다.
잘 만들어지지 않으면 만들어져있는 프로젝트로부터 main.dart 파일을 수정해서 사용하도록 한다.
모든 코드는 특정 파일을 언급하지 않으면 main.dart 파일에 들어간다.

스마트폰 앱을 만들어주는 마술같은 첫 번째 코드를 입력해 보자.

import 'package:flutter/material.dart';

void main() {
runApp(MaterialApp(
title: '첫 번째',
home: Text('처음'),
));
}

처음에는 "뭐, 이런 게 있나!" 싶을 정도로 어색하다.
100% 공감한다.
그런데 며칠 하다 보니까 나름 타협할 수 있는 방법도 있고 해서
꼭 욕을 하면서 코딩할 필요는 없겠다는 생각이 들었다.

import 키워드는 필요한 라이브러리를 사용하기 위해 필요하다.
다트는 어찌 보면 C언어의 후손처럼 느껴지기도 하는데..
반드시 main 함수가 있어야 한다.
main 함수는 매개변수를 가질 수도 있는데.. 스마트폰이니까 무시하면 된다.

main 함수의 역할은 앱을 구동하는 것이다.
runApp 함수가 그 역할을 하고 보여주고 싶은 객체를 전달하면 된다.
MaterialApp 클래스
구글의 안드로이드 앱에서 지향하는 머티리얼 디자인을 적용해 준다.
아이폰과 안드로이드의 디자인을 따로 갈 것이 아니라면
익숙해질 때까지는 머티리얼 디자인을 사용하는 게 좋다고 생각한다.
여기서는 마지막까지도 머티리얼만 사용하려고 작정하고 있다.

MaterialApp 클래스 생성자를 호출해서 객체를 생성하는데
이전 버전에서는 new 키워드를 사용해야 했지만
다트 2.0부터는 new와 const 키워드를 사용하지 않아도 된다.
여기서는 전혀 사용하지 않지만
다른 곳에서는 많이 보게 될거니까.. 그때 놀라지 말자.

파이썬의 키워드 인자처럼 매개변수의 이름을 함수에 전달할 수 있다.
함수를 정의할 때 어떻게 했는지에 따라 결정되지만
대부분은 전달한다고 보면 된다. 궁금하면 생략해 보자. 에러가 날 것이다.

title 매개변수는 앱의 설명을 가리키는데
안드로이드에서는 앱이 태스크 매니저에 표시될 때 사용되지만
아이폰에서는 사용되지 않는다.
코드 상에서는 일부러 '첫 번째'와 '처음'으로 다른 문자열을 전달했다.
다트는 문자열을 표시할 때 작음 따옴표와 큰 따옴표를 같이 쓴다. 파이썬처럼.
다트 표준은 작은 따옴표를 쓰는 것 같다. 큰 따옴표를 잘 볼 수 없다.

home은 화면에 표시될 객체(widget)을 가리킨다.
처음이라서 간단한 텍스트를 표시한다.
정말 중요한 것 하나! 내가 매번 실수하는 것!
문자열을 전달할 때는 Text 클래스로 감싸야 에러가 안 난다.
title에서처럼 문자열만 전달하는 경우는 거의 없고
화면에 문자열을 표시하기 위한 것이 대부분이기 때문에 Text 위젯을 전달하는 것이 맞다.
생략하면 에러.

다트에서 특별한 문법 중의 하나가 매개변수 뒤에 쉼표(,)를 쓸 수 있다는 점이다.
매개변수가 두 개라면 쉼표는 하나만 있어야 하지만
두 번째 매개변수 뒤에 쉼표가 있어도 된다.
MaterialApp 생성자의 매개변수를 보면
각각의 매개변수를 한 줄에 하나씩 썼는데 이게 다트 표준이다.
이때 줄의 마지막에 쉼표가 있는게 에러도 줄여주지만 가독성에도 도움이 된다.
불평하지 말고 익숙해지도록 타이핑이나 많이 하자.

참.. 구글 표기법에서는 들여쓰기를 두 칸씩 하는데
이것만은 도저히 견딜 수가 없어서 나는 모두 4칸 들여쓰기를 한다.
어쩌면 매개변수를 다음 줄에 표기하는 다트에서는 두 칸이 맞을 수도 있지만
그래도 적응이 되지 않아서 내 마음대로 한다.

코딩이 끝났으면 실행해야 한다.
메뉴 상단에 보면 아이폰 시뮬레이터와 안드로이드 에뮬레이터를 선택하는 드롭다운 메뉴가 있다.
아래 그림에서는 "Android SDK built for x86"이라고 되어 있다.


드롭다운 메뉴를 선택하면 아래와 같은 메뉴가 뜬다.
메뉴 하단에 시뮬레이터와 에뮬레이터를 여는 메뉴가 있다.
먼저 눌러서 연 다음에 상단에서 열려있는 디바이스를 선택하면 된다.
아래 그림에서는 아이폰을 충전하는 중이라 실제 아이폰까지 디바이스로 잡혀 있다.

선택이 끝났으면 실행해서 결과를 확인하자.
사실 이 예제를 만들 때는 에러가 날 수도 있겠다고 생각했는데
아무런 문제도 없었다.
그냥 형편 없었을 뿐이다. 그래도 죽지 않은게 어디인가!


참.. 화면 캡쳐가 필요하면 안드로이드 위주로 할 생각이다.
플러터의 기능 중에 hot reload라는 기능이 있는데
이게 아이폰에서는 동작하지 않는다.
가상머신과 관련된 부분이어서 그런 것 같다.
메뉴에서 노란 색으로 된 번개 아이콘이 hot reload 메뉴다.
이걸 선택하면 수정한 부분에 대해서만 반영되기 때문에
실행을 기다리지 않아도 되는 진짜 좋은 기능이다.


이제 두 번째 코드다.
앞의 사진에 나온 것과 같은 코드를 입력해 보자.

import 'package:flutter/material.dart';

void main() {
runApp(MaterialApp(
title: '첫 번째',
home: Scaffold(
appBar: AppBar(title: Text('처음'),),
),
));
}


Scafold 클래스를 사용해서
상단 제목을 보여주고 머티리얼 디자인까지 앱에 적용해 본다.
어떤가?
계속 들여쓰니까 거의 미칠 것 같은 느낌이 들지 않는가?
복사해서 붙여넣고 있는건가?

Scafold 클래스는 앱의 위쪽, 가운데, 아래쪽에 대해 미리 정리를 해놓은 클래스로
이걸 사용하면 별 생각없이 쉽게 코딩이 가능하다.
당연히 Scafold 클래스 없이 직접 구성할 수 있지만
그건 정말 나중으로 미루기로 하자.

왼쪽이 안드로이드, 오른쪽이 아이폰이다.
아이폰은 특별히 가장 최신의 아이폰 XR을 사용했다.


지금까진 별도의 클래스 없이 main 함수에서만 코딩을 했다.
이제 실제 클래스를 하나 만들어서 main 함수와 연동해 보자.

import 'package:flutter/material.dart';

void main() {
runApp(MaterialApp(
title: '첫 번째',
home: Scaffold(
appBar: AppBar(title: Text('처음'),),
body: MyApp(),
),
));
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text('텍스트 위젯');
}
}

StatelessWidget 클래스를 상속 받아서 MyApp 클래스를 정의했다.
StatelessWidget은 단어가 주는 의미 그대로 상태를 갖지 않는다.
쉬운 말로는 화면에 표시되지 않는다. 그래서 상태를 갖는 위젯이 있어야 한다.
build 함수는 반드시 구현해야 하고
여기서 위젯을 중첩시켜서 원하는 화면을 만들어서 반환하면 Scafold에 연결된다.

Scafold 클래스 생성자에 body 매개변수를 추가했고
new 키워드 없이 MyApp 생성자를 호출했다.
왼쪽 상단에 조그맣게 '텍스트 위젯' 문자열이 표시된 것을 볼 수 있다.


텍스트를 화면 가운데로 옮기려면 Center 위젯이 필요하다.
Center 위젯 말고도 여러 가지 방법이 있겠지만, 한가운데를 뜻한다면 Center 위젯이 답이다.

import 'package:flutter/material.dart';

void main() {
runApp(MaterialApp(
title: '첫 번째',
home: Scaffold(
appBar: AppBar(title: Text('처음'),),
body: MyApp(),
),
));
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text('텍스트 위젯'),
);
}
}

Center 위젯의 매개변수로 child를 사용했는데, 정말 중요하다.
위젯 안에 위젯을 넣어서 중첩시켜서 복잡한 형태의 위젯을 만드는데
자식을 하나만 가질 때는 child, 여러 개 가질 때는 children을 사용한다.
두 개를 다 가질 수는 없고 둘 중의 하나만 갖게 된다.
Center 위젯은 자식을 하나밖에 못갖기 때문에 child 매개변수를 사용한다.


같은 기능을 하는 조금 다른 코드를 보자.

import 'package:flutter/material.dart';

void main() {
runApp(MaterialApp(
title: '첫 번째',
home: MyApp(),
));
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('처음'),),
body: Center(child: Text('텍스트 위젯'),),
);
}
}

이 코드는 Scafold 클래스 객체를 생성하는 위치를 MyApp 클래스 내부로 옮겼다.
개인적으로는 Scafold 클래스 생성은 중요한 부분이 아니라서 main 함수 안쪽에 놓는 걸 좋아하는데
다른 코드를 볼 때는 지금과 같은 코드를 볼 수도 있으니 알아두자.

'플러터' 카테고리의 다른 글

5. 플러터 : 텍스트 집합 (Row, Column)  (0) 2019.02.02
4. 플러터 : 텍스트 집합 (Stack)  (0) 2019.02.02
3. 플러터 : 텍스트 스타일 (2)  (0) 2019.02.02
2. 플러터 : 텍스트 스타일 (1)  (0) 2019.02.02
0. 플러터  (0) 2019.02.01