오준석의 플러터 생존 코딩 : Flutter와 Dart 입문부터 안드로이드와 iOS용 3가지 앱 개발까지

Page 1

★★★★★★ ★ ★★

앱을 만드는 ‘완벽한 준비’에 시간을 낭비하지 마세요. 이 책은 기본을 빠르게 익히고 앱을 직접 만들며 필요한 기능을 알아가

유튜브, 블로그, 학원, 대학 등에서 이미 검증된 강의 본

는 ‘입문 + 활용서’로서 여러분의 시간을 아껴줍니다. ‘다트 언어 + 플러터 + 안드로이드 스튜디오 + 앱 개발’을 한 권으로 전

연의 장점을 극대화하고 더 체계화해 책으로 담았습니다.

달하므로, 다트(Dart) 언어와 플러터(Flutter)를 몰라도 빠르게 배워 앱을 만들 수 있습니다. 또한 입문자 눈높이에서 설명하며

입문자 눈높이에서 설명하고 작고 실용적인 프로젝트를

차츰 높은 난도의 앱을 완성해나가므로 초보자도 책을 완독할 수 있습니다. 이 책에서 제공하는 3가지 앱을 만들다 보면 플러

수행해 실전 능력을 키워줍니다. 빠르게 개발 능력을 배

터로 앱을 개발하는 데 필요한 실무 능력을 제대로 갖추게 될 겁니다.

우려는 입문자와 더 다양한 경험을 쌓으려는 기존 개발자 에게 유용합니다.

쉬워서

실용적이라서

시종일관 입문자 눈높이 설명

개념을 제시하면서도 완벽한 따라 하기 구현

실전에 유용한 3가지 실용 앱 개발

이 책에서 만들어보는 앱

추천사

비만도 계산기

■ 이

스톱워치

할 일 관리

책은 다트 언어와 위젯에 쉽게 익숙해지도록 구성되어 누구라도 앱을 만들 수 있게 해줍니다. 또한 저자가 검증

하고 실무에 사용하는 솔루션 코드로 가득해 입문자뿐 아니라 기존 앱 개발자에게도 ‘사이다’ 같은 책이 될 겁니다.

역시 플러터는 『오준석의 플러터 생존코딩』

한 번 코딩으로 안드로이드와 iOS 앱을 개발할 수 있는 플러터의 매력을 이 책과 함께 만끽하시기 바랍니다.

오준석 지음

초보자 중심이라서

플러터 생존코딩

이 시리즈는 단기간에 실무 능력을 갖추게 도와줍니다.

★★ ★ ★★

★★

★★

★★★★★★

★★ ★

★★★★★★

<소문난 명강의>시리즈 소개

오준석의

소문난 명강사 ‘오준석’이 안드로이드·iOS 앱 개발자에게 보내는 선물 같은 책

★★★★★★

★★ ★

소문난 명강의

★★★★★ ★★

★★★★★★

★★★★★

★★★★★★ ★ ★★

★★★★★ ★★

★★

소문난 명강의

★★★★★

★★

★ ★★ ★

★ ★★ ★

★★★★★★ 지은이_ 오준석 a811219@gmail.com

{

오준석의

플러터 생존코딩

문주현 블루애플 안드로이드 개발자

Flutter와 Dart 입문부터 안드로이드와 iOS용 3가지 앱 개발까지 오준석 지음

관련 도서

소문난 명강의 :

처음 배우는 플러터

오준석의 안드로이드 생존코딩

스위프트 프로그래밍 (3판)

예제 소스 github.com/junsuk5/flutter_basic

IT전문서 / 모바일 프로그래밍

정가 28,000원

{

교육하고 책 쓰는 개발자. 일본에서 개발자로 생활하다 2010년에 귀국해 안드로이드 앱을 개발합니다. 일본 테크시드, 토카이리카, LG전자 등에서 근무했습니다. 현재는 앱을 개발하고, 온라인 교육 플랫폼 인프런에서 온라인 강의를, 세민직업전문학교에서 오프라인 강의 를 합니다. 저서로 『소문난 명강의 : 오준석의 안드로이 드 생존코딩』(한빛미디어, 2018), 『될 때까지 안드로이 드』(루비페이퍼, 2018)가 있습니다.

유튜브 (안드로이드 생존코딩) youtube.com/c/안드로이드생존코딩 온라인 강의 플랫폼 survivalcoding.com


★ ★★★★★

★ ★ ★★ ★ ★ ★

소문난 명강의

★ ★★ ★ ★ ★ ★★ ★

★★

★★

★★★★★★

오준석의 플러터 생존코딩 Flutter와 Dart 입문부터 안드로이드와 iOS용 3가지 앱 개발까지

초판1쇄발행 2020년 03월 01일 지은이 오준석 / 베타리더 문주현 / 펴낸이 김태헌 펴낸곳 한빛미디어 (주) / 주소 서울시 서대문구 연희로2길 62 한빛미디어(주) IT출판부 전화 02 – 325 – 5544 / 팩스 02 – 336 – 7124 등록 1999년 6월 24일 제 25100 -2017-000058호 / ISBN 979 -11-6224-283 -4 93000 총괄 전정아 / 책임편집 이상복 / 기획 최현우 / 편집·조판 김철수 디자인 표지·내지 김연정 영업 김형진, 김진불, 조유미 / 마케팅 박상용, 송경석, 조수현, 이행은, 홍혜은 / 제작 박성우, 김정우 이 책에 대한 의견이나 오탈자 및 잘못된 내용에 대한 수정 정보는 한빛미디어(주)의 홈페이지나 아래 이메일로 알려주십시오. 잘못된 책은 구입하신 서점에서 교환해드립니다. 책값은 뒤표지에 표시되어 있습니다. 한빛미디어 홈페이지 www.hanbit.co.kr / 이메일 ask@hanbit.co.kr

Published by Hanbit Media, Inc. Printed in Korea Copyright © 2020 오준석 & Hanbit Media, Inc. 이 책의 저작권은 이제민과 한빛미디어(주)에 있습니다. 저작권법에 의해 보호를 받는 저작물이므로 무단 복제 및 무단 전재를 금합니다.

지금 하지 않으면 할 수 없는 일이 있습니다. 책으로 펴내고 싶은 아이디어나 원고를 메일 ( writer@hanbit.co.kr ) 로 보내주세요. 한빛미디어(주)는 여러분의 소중한 경험과 지식을 기다리고 있습니다.


★★ ★ ★ ★

★ ★ ★ ★ ★★ ★

★★ ★

소문난 명강의

★★

★★★★★★ ★ ★★

★★★★★★

{

오준석의

플러터 생존코딩

{

오준석 지음

소문난 명강의 시리즈 소개 이 시리즈는 단기간에 실무 능력을 갖추게 도와줍니다. 유튜브, 블로그, 학원, 대학 등에서 이미 검증된 강의 본연의 장점을 극대화하고 더 체계화해 책으로 담았습니 다. 입문자 눈높이에서 설명하고 작고 실용적인 프로젝트를 수행해 실전 능력을 키 워줍니다. 빠르게 개발 능력을 배우려는 입문자와 더 다양한 경험을 쌓으려는 기존 개발자에게 유용합니다.


지은이의 말

지난 10년간 모바일 앱 개발 플랫폼은 안드로이드와 iOS로 양분화되어 발전했습니다. 모바일 앱 시장도 덩달아 성장해 안드로이드와 iOS 개발자 수요는 여전히 많습니다. 저는 이러한 수요 에 힘입어 지난 10년간 안드로이드 개발과 교육을 주로 해왔으며 때로는 iOS 개발도 했습니다. 서비스를 기획하여 제품으로 만드는 데 홈페이지와 더불어 모바일 앱은 필수입니다. 그런데 모 바일 앱을 만들려면 안드로이드와 iOS 앱을 각각 만들어야 합니다. 그러려면 각 플랫폼 개발 환경에서 사용하는 언어를 알아야 합니다. 안드로이드는 자바 또는 코틀린을 배워야 하고, iOS 는 스위프트 또는 오브젝티브-C를 배워야 합니다. 이 경우 일반적으로 서비스 하나를 앱으로 제공하려면 개발자가 최소 2명 필요합니다. 한 번 개발로 안드로이드와 iOS 앱을 한 번에 대응하려는 바람은 모바일 앱 초기부터 있었습 니다. 다양한 크로스 플랫폼 프레임워크가 등장하고 사라졌으며, 2017년 5월 구글에서 플러터 Flutter

를 발표했습니다. 플러터를 만나기 전까지 네이티브 앱이 항상 최고의 퍼포먼스를 이끌어

낸다고 알고 있기에 네이티브 개발을 고집했는데 플러터를 접하고 나서 가능성을 보게 되었습 니다. 일단 코딩이 너무 즐거웠습니다. 쉬웠기 때문입니다. 하지만 플러터로 복잡한 서비스를 개발하다 보니 불안감이 스멀스멀 올라왔습니다. “역시 네이티브가 답이야. 아냐 플러터가 더 좋은 것 같아.” 앱을 개발하면서 플러터에 대한 신뢰가 수없이 엇갈렸습니다. 개인적인 결론을 먼저 말씀드리 겠습니다. 생산성과 퍼포먼스를 모두 생각했을 때 반드시 네이티브가 정답은 아니었습니다. 개 발하려는 서비스에 강력한 성능이 꼭 필요하지 않다면 반드시 네이티브 앱 개발을 고집할 필요 는 없습니다. 플러터가 있으니까요. 온라인과 오프라인 강의를 진행하면서 초보자도 플러터라면 더 쉽게 앱 개발을 시작할 수 있겠 다는 확신이 생겼습니다. 벌써 제 주변 몇몇 업체도 플러터를 사용해 앱 개발을 시작했습니다. 특히 중소기업에서 플러터에 대한 수요가 늘어날 것으로 보입니다.

004


이 책을 통해 앱 개발에 실패했던 사람도 입문하는 사람도 재미있게 앱 개발을 할 수 있는 계기 가 되길 바랍니다.

오준석

a811219@gmail.com

교육하고 책 쓰는 개발자. 일본에서 개발자로 생활하다 2010년에 귀국해 안드로이드 앱을 개발합니다. 일본 테크시드, 토카이리카, LG전자 등에서 근무했습니다. 현재는 앱 을 개발하고, 온라인 교육 플랫폼 인프런에서 온라인 강의를, 세민직업전문학교에서 오프라인 강의를 합니다. 저서로 『소문난 명강의 : 오준석의 안드로이드 생존코딩』(한 빛미디어, 2018), 『될 때까지 안드로이드』(루비페이퍼, 2018)가 있습니다. 유튜브 채널(안드로이드 생존코딩) : youtube.com/c/안드로이드생존코딩 온라인 강의 플랫폼(오준석의 생존코딩) : survivalcoding.com/

005


이 책의 특징

입문자와 초보자를 배려한 진행 순서 이 책은 프로그래밍 초보자와 모바일 앱 개발 입문자를 대상으로 합니다. 되도록 쉬운 표현으로 누구나 앱을 개발할 수 있게 설명합니다. 초보자 중심 입문자나 초보자에게 ‘앱을 만들 수 있다’는 자신감을 심어주는 것이 목표입니다. 올인원 패키지 플러터 동작 원리, 다트 프로그래밍, 객체 지향, 함수형 프로그래밍, 파이어베이스 등을 다룹니 다. 이 책 한 권으로 플러터와 다트 입문서를 모두 대체할 수 있습니다. 예제 난이도 안내 예제 난이도를 별 개수로 표현했습니다. 초급 - ★☆☆ 중급 - ★★☆ 고급 - ★★★

006


이 책이 다루는 범위

이 책이 다루는 범위는 다음과 같습니다. 개발 환경 _ 개발 환경 구성 방법을 다룹니다. _ 안드로이드 스튜디오 사용 방법을 다룹니다. _ 플러터 플러그인 설치 방법을 다룹니다. 플러터 앱 동작 방식 _ 플러터 프로젝트의 구성을 다룹니다. _ 기본 샘플 앱을 분석해가며 플러터 앱 동작 방식을 이해합니다. 레이아웃 작성 _ 플러터로 앱의 UI를 작성하는 방법을 다룹니다. _ 자연스럽게 플러터 앱 개발 패턴을 다룹니다. 화면 이동 _ 화면 이동 방식을 이해합니다. _ 화면 이동을 할 때 데이터도 함께 전달하는 방법을 다룹니다. 다트 언어 _ 변수, 메서드, 클래스 등 기본 문법을 다룹니다. _ 함수형 프로그래밍, 비동기 프로그래밍 등 고급 문법을 다룹니다. 그외 _ 플러터 이해를 돕는 간단한 샘플 예제를 다룹니다. _ 클라우드 서비스인 파이어베이스를 사용하여 실전 앱 예제를 다룹니다.

007


개발 환경과 예제 파일

개발 환경 _ 이 책의 모든 예제는 플러터 1.12.13 버전과 다트 2.7.0 버전에서 작성했습니다. _ 맥과 윈도우 환경에서 정상 동작하는 것을 확인했습니다. _ 스크린샷은 맥 기준으로 소개하지만 윈도우 환경과 차이점은 없습니다. 예제 파일 다운로드 이 책의 예제는 저자의 깃허브와 한빛미디어 홈페이지에서 다운로드할 수 있습니다. •깃허브 : github.com/junsuk5/flutter_basic •한빛미디어 : www.hanbit .co.kr/src/10283

깃허브에서 예제 코드를 다운로드하는 방법은 다음과 같습니다. 1

웹 브라우저로 github.com/junsuk5/flutter_basic에 접속합니다.

2

‘Clone or download’를 클릭합니다.

3

‘Download ZIP’을 클릭하여 압축 파일을 다운로드하고 적당한 위치에 압축을 풉니다. 2

3

압축을 풀면 각 장에 대한 폴더가 생성됩니다(예제 프로젝트를 작성하지 않는 장은 폴더가 없 습니다).

008


예제 파일 실행 방법 안드로이드 스튜디오 메뉴에서

1

‘File > Open’을 클릭하고 다운로드한 예제 폴더를 엽니다.

4장과 10장의 프로젝트는 별도의 라이브러리를 사용하므로 프로젝트를 연 후 yaml 파일을 열고

3

2

pubspec.

Packages get을 실행해야 합니다.

3

2

009


개발 환경과 예제 파일

4장과 5장의 예제를 앱 형태로 제공해 동작과

4

010

4

깃허브 소스를 쉽게 확인할 수 있습니다.


이 책의 구성

이 책은 플러터와 다트를 학습하고 총 3가지 실용 앱을 개발합니다. 1부 ‘플러터에 입문하기’ (0~7장)에서는 플러터와 다트를 이해하는 데 필요한 기초 내용을 알아보고 복잡한 UI를 작성 해봅니다. 2부 ‘플러터로 앱 개발하기’(8~10장)에서는 3가지 앱을 만들어보며 플러터로 앱을 개발하는 방법을 알아봅니다.

1부 플러터에 입문하기 0장 : 플러터 개발 환경 준비하기

플러터에 대해 알아보고 플랫폼별 개발 환경을 준비합니다. 1장 : 생애 첫 모바일 앱 생성하기

프로젝트 생성 방법과 에뮬레이터 또는 실제 기기에서 실행하는 방법을 배웁니다. 2장 : 다트 문법

다트 프로그래밍을 배웁니다. 앱이 원하는 대로 동작하려면 프로그래밍이 필요합니다. 플러터 에서 주로 사용되는 대부분의 문법을 익힙니다. 3장 : 프로젝트와 앱 구조

첫 플러터 프로젝트를 생성하고 샘플 앱을 분석하면서 플러터 프로젝트의 동작 방식을 이해합 니다. 4장 : 기본 위젯 I

플러터가 제공하는 다양한 머티리얼 기본 위젯을 빠르게 훑어봅니다. 5장 : 기본 위젯 II

사용자와 상호작용하는 위젯, 애니메이션 지원 위젯, iOS 스타일의 쿠퍼티노 위젯을 배웁니다. 6장 : 내비게이션

화면 전환을 하고 데이터를 전달하는 방법을 배웁니다. 플러터에서는 화면 전환을 ‘내비게이션’ 이라고 부릅니다. 011


이 책의 구성

7장 : 복잡한 UI 작성 ★☆☆

플러터로 처음부터 하나씩 UI를 작성하면서 다양한 위젯을 다루는 방법을 배웁니다. 따라하다 보면 자연스럽게 플러터 앱 개발 방법을 배우게 됩니다.

2부 플러터로 앱 개발하기 8장 : 비만도 계산기 ★☆☆

키와 몸무게를 입력하면 비만도를 표시해주는 앱을 만듭니다. 플러터로 UI와 프로그래밍을 함 께 다루는 첫 장입니다. 화면 전환을 하고, 데이터를 전달하고, 계산하여 결과를 도출하는 방법 을 배웁니다.

9장 : 스톱워치 ★★☆

스톱워치 앱을 만듭니다. 일정 주기로 반복되는 동작을 어떻게 구현하는지 배웁니다. 버튼을 눌렀을 때 UI가 변경되는 다이내믹한 처리도 배웁니다.

012


10장 : 할 일 관리 ★★★

기본적인 할 일 관리 앱을 작성하고, 서버 없이도 서버의 기능을 사용할 수 있는 파이어베이스 서비스를 활용하여 클라우드 DB에 저장하는 앱을 만드는 방법을 배웁니다.

013


이 책의 모태 사이트 소개

유튜브 채널(안드로이드 생존코딩) 유튜브 채널은 5,000명이 넘는 구독자를 보유하고 있으며 안드로이드 네이티브와 플러터 관련 영상을 주로 업로드합니다. 유튜브에는 ‘될 때까지 안드로이드’, ‘Flutter 입문’, ‘Flutter 중급’, ‘모던 안드로이드’ 시리즈를 업로드했습니다. 그 외 다양한 장르의 개발 관련 영상을 업로드합 니다. • 유튜브 채널 : youtube.com/c/안드로이드생존코딩

014


온라인 강의 플랫폼(오준석의 생존코딩) 오준석의 생존코딩이라는 개인 유료 강좌 플랫폼을 운영합니다. 온라인 강의 플랫폼 인프런에서 베스트셀러로 판매되는 ‘Flutter 입문’, ‘Flutter 중급’ 강좌를 오준석의 생존코딩에서도 제공합 니다. • 오준석의 생존코딩 : survivalcoding.com

‘Flutter 입문’ 온라인 강좌는 인프런에서 600개, 생존코딩에서 80개 넘게 판매되었고, 구글의 파이어베이스를 활용한 인스타그램 따라하기 예제를 다룹니다. ‘Flutter 중급’ 온라인 강좌는 인 프런에서만 300개 넘게 판매되었고 네트워크 통신, 상태 관리를 다룹니다. 동영상 강의와 책은 소개하는 내용의 범위나 정보를 제공하는 방식이 다르므로 상호보완적입니다. 따라서 이미 온라인 강좌로 수업을 들었더라도 요약, 정돈된 개발 정보를 제공하는 이 책이 도움 이 될 겁니다. 반대로 책을 먼저 보더라도 저자의 동영상 강의가 도움이 될 겁니다.

015


목차

1부

지은이의 말 ������������������������������������������������������������������������������� 004

이 책의 특징 ������������������������������������������������������������������������������ 006

이 책이 다루는 범위 �������������������������������������������������������������������� 007

개발 환경과 예제 파일 ����������������������������������������������������������������� 008

이 책의 구성 ������������������������������������������������������������������������������ 011

이 책의 모태 사이트 소개 ������������������������������������������������������������ 014

0장 플러터 개발 환경 준비하기 ���������������������������������������������������� 023

플러터에 입문하기

025

0.3 개발 환경 구성 ����������������������������������������������������������������������������� 026 0.4 마치며 �����������������������������������������������������������������������������������������

1장 생애 첫 모바일 앱 생성하기 ��������������������������������������������������� 035

1. 1 프로젝트 생성 ������������������������������������������������������������������������������ 036 1.2 안드로이드용 프로젝트 �����������������������������������������������������������������

034

041

1.3 iOS용 프로젝트 ��������������������������������������������������������������������������� 054 1.4 마치며 ����������������������������������������������������������������������������������������� 057

2장 다트 문법 ���������������������������������������������������������������������������������� 059

2. 1 다트 언어 연습 환경 ��������������������������������������������������������������������� 060 2.2 기본 문법 ������������������������������������������������������������������������������������

061

�������������������������������������������������������������������������������������������� 2.3 함수 068 ��������������������������������������������������������������������������������� 2.4 분기와 반복 074 2.5 객체 지향 프로그래밍 �������������������������������������������������������������������

076

2.6 컬렉션 ����������������������������������������������������������������������������������������� 084 2.7 함수형 프로그래밍 ����������������������������������������������������������������������� 087 2.8 기타 유용한 기법 ��������������������������������������������������������������������������

2.9 마치며 ����������������������������������������������������������������������������������������� 097

016

0. 1 앱 개발 방식 소개 ������������������������������������������������������������������������� 024 0.2 플러터 소개 ���������������������������������������������������������������������������������

094


3장 프로젝트 구조와 앱 구조 �������������������������������������������������������� 099

3. 1 프로젝트 구조 이해 ���������������������������������������������������������������������� 100 3.2 샘플 앱 분석하기 ��������������������������������������������������������������������������

101

3.3 실습 �������������������������������������������������������������������������������������������� 113 ����������������������������������������������������������������������������������������� 3.4 마치며 118

4장 기본 위젯 I ������������������������������������������������������������������������������� 121

4. 1 예제를 연습하는 방법 ������������������������������������������������������������������� 122 4.2 화면 배치에 쓰는 기본 위젯 �����������������������������������������������������������

126

4.3 위치, 정렬, 크기를 위한 위젯 ��������������������������������������������������������� 141 4.4 버튼 계열 위젯 ����������������������������������������������������������������������������� 149 4.5 화면 표시용 위젯 ��������������������������������������������������������������������������

4.6 마치며 ����������������������������������������������������������������������������������������� 158

5장 기본 위젯 II ������������������������������������������������������������������������������ 159

5. 1 입력용 위젯 ��������������������������������������������������������������������������������� 160 5.2 다이얼로그 ����������������������������������������������������������������������������������

152

168

5.3 이벤트 ����������������������������������������������������������������������������������������� 174 5.4 애니메이션 ����������������������������������������������������������������������������������

177

5.5 쿠퍼티노 디자인 ��������������������������������������������������������������������������� 185 5.6 마치며 �����������������������������������������������������������������������������������������

6장 내비게이션 ������������������������������������������������������������������������������� 193

6. 1 새로운 화면으로 이동 ������������������������������������������������������������������� 194 를 활용한 내비게이션 ��������������������������������������������������������� 6.2

routes

191

201

6.3 내비게이션 동작 방식의 이해 ��������������������������������������������������������� 202 6.4 마치며 ����������������������������������������������������������������������������������������� 208

017


목차

7장 복잡한 UI 작성 ������������������������������������������������������������������������ 209

7. 1 해법 요약 ������������������������������������������������������������������������������������ 211 7.2 스텝 : 뼈대 작성 ������������������������������������������������������������������������

3

UI

218

7.6 생산성을 높여주는 단축키 ������������������������������������������������������������� 220 7.7 스텝 5 : 상단 부분 ������������������������������������������������������������������������ 223 7.8 스텝 : 중단 부분 ������������������������������������������������������������������������

6

230

8장 비만도 계산기 �������������������������������������������������������������������������� 243

플러터로 앱 개발하기

239

8. 1 해법 요약 ������������������������������������������������������������������������������������ 245 8.2 준비하기 �������������������������������������������������������������������������������������

246

8.3 스텝 1 : 기본 코드 작성 ���������������������������������������������������������������� 252 8.4 스텝 : 키와 몸무게를 입력하는 화면 작성 �������������������������������������

2

253

8.5 스텝 3 : 결과 화면 작성 ���������������������������������������������������������������� 255 8.6 스텝 : 값 검증 및 화면 전환 ��������������������������������������������������������

4

257

8.7 스텝 5 : 결과 표시 ������������������������������������������������������������������������ 262 8.8 마치며 �����������������������������������������������������������������������������������������

9장 스톱워치 ����������������������������������������������������������������������������������� 267

9. 1 해법 요약 ������������������������������������������������������������������������������������ 269 작성 ��������������������������������������������������������������������������� 9.2 스텝 :

9.3 스텝 2 : 타이머 구현하기 �������������������������������������������������������������� 275

9.4 스텝 3 : 랩타임 기록하기 �������������������������������������������������������������� 280 9.5 마치며 �����������������������������������������������������������������������������������������

018

4

7.9 스텝 7 : 하단 부분 ������������������������������������������������������������������������ 237 7.10 마치며 �����������������������������������������������������������������������������������������

2부

212

1

7.3 스텝 2 : BottomNavigationBar 위젯을 이용한 하단 탭 구성 ���������� 213 ���������������������������������������������������������� 7.4 스텝 3 : AppBar 위젯 수정 215 작성 ������������������������������������������������������� 7.5 스텝 : 화면이 개인

266

1 UI

269

282


10장 할 일 관리 ��������������������������������������������������������������������������������� 283

10. 1 해법 요약 ������������������������������������������������������������������������������������ 285 10.2 스텝 : 할 일 관리 앱 기본 버전 작성 ��������������������������������������������

1

287

10.3 스텝 2 : 파이어베이스 설정 ����������������������������������������������������������� 295 ���������������������������������������� 10.4 스텝 3 : Firestore를 활용하여 기능 수정 305 ����������������������������������������������������������������������������������������� 10.5 마치며

317

찾아보기 ������������������������������������������������������������������������������������������������� 318

019



1부

플러터에 입문하기 0장 플러터 개발 환경 준비하기 1장 생애 첫 모바일 앱 생성하기 2장 다트 문법 3장 프로젝트 구조와 앱 구조 4장 기본 위젯 I 5장 기본 위젯 II 6장 내비게이션 7장 복잡한 UI 작성


1부에서 다루는 내용

1부에서는 플러터와 다트를 이해하는 데 필요한 기초 내용을 알아보고 복잡한 UI를 작성해봅 니다. 0장 : 플러터 개발 환경 준비하기

플러터에 대해 알아보고 플랫폼별 개발 환경을 준비합니다. 1장 : 생애 첫 모바일 앱 생성하기

프로젝트 생성 방법과 에뮬레이터 또는 실제 기기에서 실행하는 방법을 배웁니다. 2장 : 다트 문법

다트 프로그래밍을 배웁니다. 앱이 원하는 대로 동작하려면 프로그래밍이 필요합니다. 플러터 에서 주로 사용되는 대부분의 문법을 익힙니다. 3장 : 프로젝트와 앱 구조

첫 플러터 프로젝트를 생성하고 샘플 앱을 분석하면서 플러터 프로젝트의 동작 방식을 이해합 니다. 4장 : 기본 위젯 I

플러터가 제공하는 다양한 머티리얼 기본 위젯을 빠르게 훑어봅니다. 5장 : 기본 위젯 II

사용자와 상호작용하는 위젯, 애니메이션 지원 위젯, iOS 스타일의 쿠퍼티노 위젯을 배웁니다. 6장 : 내비게이션

화면 전환을 하고 데이터를 전달하는 방법을 배웁니다. 플러터에서는 화면 전환을 ‘내비게이션’ 이라고 부릅니다. 7장 : 복잡한 UI 작성

플러터로 처음부터 하나씩 UI를 작성하면서 다양한 위젯을 다루는 방법을 배웁니다. 따라하다 보면 자연스럽게 플러터 앱 개발 방법을 배우게 됩니다.

022

1부 플러터에 입문하기


0장 플러터 개발 환경 준비하기 0.1 앱 개발 방식 소개

0.2 플러터 소개

0.3 개발 환경 구성 0.4 마치며

0장 플러터 개발 환경 준비하기

023


플러터를 시작하려는 당신! 탁월한 선택이라고 말씀드리고 싶네요. 먼저 플러터가 무엇인지 알 아보고 개발 환경을 구축해봅시다. 이 장에서 다루는 내용은 다음과 같습니다. • 앱 개발 방식 소개 • 플러터 소개 • 개발 환경 구성하기

0.1 앱 개발 방식 소개 스마트폰 앱은 크게 네이티브, 하이브리드, 크로스 플랫폼 방식으로 개발됩니다. 현 시점에서 사실상 스마트폰 운영체제는 안드로이드와 iOS로 양분되어 있습니다. 이 책은 두 운영체제 모 두에서 돌아가는 앱을 한 번에 구현하는 플러터를 다룹니다. 플러터처럼 멀티 플랫폼을 제공하 는 프레임워크를 사용해야 할 이유가 있을까요? 그 이유를 개발 방식별 특징을 살펴보며 알아 봅시다. 다음 그림은 개발 방식에 따른 결과물을 보여줍니다.

개발

네이티브 방식

하이브리드 방식

크로스 플랫폼 방식

운영체제별 네이티브 개발 환경

하이브리드 개발 도구 (예 : 코드바)

크로스 플랫폼 도구 (예 : 플러터)

웹 UI

네이티브

네이티브 네이티브 코어

▶ 개발 방식별 결과물

024

1부 플러터에 입문하기


네이티브 방식은 안드로이드나 iOS 같은 플랫폼 자체에서 제공하는 개발 환경으로 개발합니다.

안드로이드는 개발 도구로 안드로이드 스튜디오를, 개발 언어로 자바 또는 코틀린 Kotlin 을 사용 합니다. iOS는 맥OS 환경에서만 개발이 가능하며 개발 도구로 엑스코드 XCode, 개발 언어로 스 위프트 Swift 또는 오브젝티브-C Objective-C 를 사용합니다. 혼자서 각 플랫폼에 맞는 앱을 네이티 브 방식으로 개발하려면 알아야 할 지식이 두 배네요. 그러니 두 플랫폼에 맞는 앱을 각각 네이 티브 방식으로 혼자 개발하는 것은 쉬운 일이 아닙니다. 하이브리드 방식은 웹 기술로 앱 화면을 만든 후 네이티브 기술로 감싸서 앱 형태로 포장합니다.

기존의 웹 기술을 활용하고 빠르게 앱으로 변환할 수 있기 때문에 빠른 앱 개발을 할 수 있지만 네이티브 성능에 미치지 못하며, UI 또한 별도로 만들기 때문에 네이티브 앱 느낌을 내지 못합 니다. 크로스 플랫폼 방식은 한 번 구현하여 안드로이드와 iOS 등 각 플랫폼용 앱을 만듭니다. 이 방식

은 빌드(앱을 완성하는 과정)할 때 네이티브 코드로 변환되기 때문에 결과적으로는 네이티브 방식으로 개발했을 때와 거의 같은 성능을 보장합니다. 생산성과 품질을 모두 고려했을 때 선 호하는 방식입니다.

0.2 플러터 소개 플러터는 한 번 코딩으로 여러 플랫폼용 앱을 만드는 크로스 플랫폼 개발 프레임워크입니다. 안드로이드와 iOS뿐 아니라 웹, 데스크톱 앱 개발도 가능합니다. 장점으로는 낮은 진입장벽, 높은 네이티브 성능, 훌륭한 개발 도구 지원, 예쁜 UI를 들 수 있습니다. • 낮은 진입장벽 네이티브 개발에 비해 플러터는 배워야 할 개념이 상대적으로 적어 더 쉽게 앱 개발에 입문할 수 있습니다. • 높은 네이티브 성능 플러터로 작성된 코드는 네이티브 코드로 변환되기 때문에 성능이 네이티브 코드와 동일합니다. 다른 크로 스 플랫폼 개발 프레임워크와 다르게 화면 구성에 필요한 UI 구성 요소를 플러터가 직접 그리기 때문에 속 도가 빠릅니다. 초당 60프레임 애니메이션을 보장합니다. • 훌륭한 개발 도구 지원 안드로이드 스튜디오에서 개발할 수 있습니다. 안드로이드 스튜디오의 전신인 인텔리제이와 비주얼 스튜디 오 코드에서도 플러그인을 설치해 사용할 수 있습니다.

0장 플러터 개발 환경 준비하기

025


•예쁜 UI 안드로이드의 머티리얼 디자인과 iOS의 쿠퍼티노 디자인의 UI 구성 요소를 모두 제공합니다. 따라서 각 플 랫폼의 디자인 철학에 맞게 적절하게 조립을 해주면 됩니다. 네이티브 개발이 맨땅에 헤딩을 하는 느낌이라 면 플러터는 퍼즐을 맞춰가는 느낌으로 개발을 할 수 있습니다. 각 디자인별 디자인 철학을 알고 싶다면 다 음 링크를 참고하세요. - 머티리얼 디자인 : material.io/ - 쿠퍼티노 디자인 : developer.apple.com/design/

플러터 개발 언어로 다트 Dart 를 사용합니다. 다트는 구글에서 개발한 언어로 웹 프론트엔드 개발 언어였는데 현재는 플러터 개발에 주로 사용됩니다. 문법은 자바 또는 자바스크립트와 비슷합니 다. 2장에서 다트 기본 문법을 알아봅니다. 참고로 플러터는 구글이 개발 중인 차세대 운영체제 퓨시아 Fuchsia 의 공식 프레임워크이기도 합 니다. 따라서 앞으로는 더욱 쓰임새가 많아질 겁니다.

0.3 개발 환경 구성 플러터 개발 환경을 구성해봅시다. 다음과 같은 과정을 거칩니다. 1. 플러터 SDK (소프트웨어 개발 키트) 설치 2. 환경 변수 등록 3. 앱 개발 도구 설치

0.3.1 플러터 SDK 설치 1

플러터 웹사이트(flutter.dev )에 접속한 뒤

2

우측 상단의 ‘Get started’를 클릭합니다. 2

▶ Get started 클릭

026

1부 플러터에 입문하기


플러터를 구동해서 개발할 수 있는 운영체제는 다음과 같습니다. 32비트 운영체제에서는 정상 적으로 동작하지 않습니다. •윈도우 7 SP1 이상(64비트 버전) •맥OS •리눅스 3

다음 화면에서 자신의 PC에 설치된 운영체제를 클릭합니다.

3

3

3

▶ 사용 중인 운영체제 선택

4

각 운영체제별 페이지로 들어가 SDK 파일을 다운로드합니다.

4

▶ SDK zip 파일 다운로드 0장 플러터 개발 환경 준비하기

027


5

다운로드받은 파일을 C:\src 폴더에 압축을 풉니다. flutter 폴더로 압축되어 있어서 예를

들어 C:\src 폴더를 지정하면 C:\src\flutter에 압축이 풀립니다. 압축을 풀 때 C:\Program

Files\와 같은 높은 권한이 필요한 위치는 피하는 것이 좋습니다.

0.3.2 환경 변수 등록 플러터 명령 파일은 압축을 푼 폴더 아래 bin 폴더에 들어 있습니다. 이 파일이 들어 있는 경로 를 운영체제의 환경 변수에 등록해두면 어디에서나 플러터 명령을 사용할 수 있습니다. 환경 변수 등록 방법은 운영체제별로 조금씩 다릅니다. 자신의 운영체제에 맞게 환경 변수 등록을 해줍니다. 책에서는 윈도우와 맥OS만 다룹니다. 윈도우 윈도우 사용자 변수에 플러터 SDK 위치를 추가하면 터미널(윈도우+ R

>

cmd ) 어디에서든

플러터 명령을 사용할 수 있습니다. 1

‘검색’에 ‘환경 변수’를 입력하고

2

1

▶ 환경 변수 편집 도구 검색

028

1부 플러터에 입문하기

2

‘시스템 환경 변수 편집’을 클릭합니다.


‘시스템 속성’ 창이 뜨면

3

‘고급’ 탭에서

4

‘환경 변수(N )...’를 선택합니다.

3

4

‘환경 변수’ 창에서

5

‘Path’를 선택한 후

6

‘편집’ 버튼을 클릭합니다.

5

6

0장 플러터 개발 환경 준비하기

029


7

‘찾아보기’를 클릭하고 플러터 SDK의 bin 폴더 위치를 선택합니다.

8

‘확인’ 버튼을 눌러

설정 창을 모두 닫습니다.

7

8

▶ 사용자 변수 > Path 편집 > Flutter SDK 위치 추가 > 확인 (윈도우10)

9

‘검색’ 창에 ‘cmd’를 입력해 터미널을 실행시킨 후

10

‘flutter --version’을 입력합니다.

환경 설정이 제대로 되었다면 다음과 같이 플러터 버전을 출력할 겁니다. C:\Users\hwchoi>flutter --version Flutter 1.12.13+hotfix.7•channel stable•github.com/flutter/flutter.git Framework•revision 68587a0916 (3 months ago)•2019-09-13 19:46:58 -0700 Engine•revision b863200c37 Tools•Dart 2.7.0

맥OS, 리눅스 ~/dev/flutter에 압축을 풀었다고 가정하겠습니다. 터미널에서 다음 명령을 실행하여 현재 환 경 변수에 플러터 SDK 위치를 추가합니다.

030

1부 플러터에 입문하기


1장 생애 첫 모바일 앱 생성하기 1.1 프로젝트 생성 1.2 안드로이드용 프로젝트 1.3 iOS용 프로젝트 1.4 마치며

0장 플러터 개발 환경 준비하기

035


이 장에서는 안드로이드 스튜디오를 사용하여 프로젝트를 생성하고 에뮬레이터나 기기에서 샘 플 앱을 실행하는 과정을 알아봅니다. 안드로이드와 iOS용으로 빌드하는 방법도 소개합니다. 이 장에서 다루는 내용은 다음과 같습니다. •프로젝트 생성 방법 •iOS에서 빌드하는 방법 •flutter doctor로 개발 환경 진단하기 •에뮬레이터와 실제 기기에서 앱 실행 방법 •핫 리로드

1.1 프로젝트 생성 안드로이드 스튜디오를 이용해서 생애 첫 플러터 프로젝트를 만들어봅시다.

1

‘Welcome to

Android Studio’ 창에서 ‘Start a new Flutter project’를 클릭합니다. 개발용 PC에서 앱을 만드므로 안드로이드와 iOS 앱 모두에서 같은 과정을 거칩니다. 우선 앱을 만들고 운영체제별 로 빌드하고 실행하는 방법을 알아보겠습니다.

1

▶ Start a new Flutter project 클릭하여 프로젝트 생성

036

1부 플러터에 입문하기


‘Create New Flutter Project’ 창이 표시됩니다. 몇 가지 템플릿이 보일 겁니다.

Application’을 선택하고

3

2

‘Flutter

‘Next’ 버튼을 클릭합니다.

2

3

▶ Flutter Application 선택 > Next 클릭

프로젝트 설정 창에서 프로젝트의 기본 설정을 합니다. •Project name : 프로젝트명을 설정합니다. •Flutter SDK path : 플러터 SDK를 설치한 폴더를 지정합니다. •Project location : 프로젝트를 생성할 위치를 지정합니다. •Description : 프로젝트의 설명을 작성합니다. 4

‘Project name’은 기본값인 flutter_app 그대로 두겠습니다.

5

‘...’ 버튼을 누르고 플러터

SDK를 설치한 폴더(C:\src\flutter )를 선택합니다. 항목을 작성하였다면

6

‘Next’ 버튼을 클

릭합니다.

1장 생애 첫 모바일 앱 생성하기

037


4 5

6

▶ 프로젝트 설정 화면

다음 창에서는 패키지명을 설정합니다. 7

‘Company domain’에는 도메인이 있다면 입력합니다. 여기서는 연습용으로 ‘example.

com’을 입력합니다. 인합니다.

9

8

‘androidX ’ 아래의 ‘Use androidx.*artifacts’가 체크되어 있는지 확

‘Finish’ 버튼을 클릭해 프로젝트를 생성합니다.

컴퍼니 도메인과 앱 이름의 조합으로 패키지명이 결정됩니다. 패키지명은 앱을 나타내는 고유 한 값으로 구글 플레이 또는 앱스토어에 업로드할 때 기존에 중복되는 값이 있으면 업로드되 지 않습니다. 도메인을 보유하지 않았다면 적당한 값을 사용하여 임의로 작성합니다. 참고로

example.com 도메인은 구글 플레이에 업로드가 불가능합니다. 최근 안드로이드 진영의 큰 변화 중 하나는 AndroidX라는 새로운 버전 체계로 바뀐 겁니 다. 플러터 개발을 하다 보면 외부 라이브러리를 사용해야 하는데 최신 라이브러리는 대부분

AndroidX 기반으로 작성되어 있어서 체크해주는 것이 좋습니다.

038

1부 플러터에 입문하기


7

8

9

▶ 패키지명과 AndroidX 설정

‘Platform channel language’는 네이티브 코드와 연동하는 코드를 자바, 오브젝티브-C로 작성한다면 체크를 해제하고 코틀린, 스위프트로 작성한다면 체크를 합니다. 이 책의 범위가 아니므로 기본값으로 두었습니다.

1.1.1 환경 구성 검사 flutter doctor 명령은 플러터를 개발할 환경 구성이 잘되었는지 검사해주고 가이드를 해주는

명령입니다. flutter doctor 명령을 실행하는 방법은 세 가지입니다. 첫 번째 방법은

1

터미널에서 플러터 명령을 실행하는 겁니다. 두 번째 방법은

2

안드로이드

스튜디오 하단에 있는 ‘Terminal’ 탭을 눌러서 터미널을 실행하고 flutter doctor 명령을 직 접 입력하는 겁니다. 이 두 방법은 윈도우에 환경 변수를 등록해야 작동합니다(이미 우리는 0장 에서 환경 변수를 등록했습니다).

1장 생애 첫 모바일 앱 생성하기

039


현 시점에서 flutter doctor 명령을 실행하면 다음과 같이 라이선스와 기기 관련해서 문제가 있다고 표시됩니다. 이 문제들을 해결하는 방법은 뒤에서 다시 설명하겠습니다. [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.1 19B88, locale ko-KR) [✓] Android Studio (version 3.5) [!] Android toolchain - develop for Android devices (Android SDK version 27.0.3) ✗ Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses [!] Connected device ! No devices available

세 번째 방법은

3

왼쪽 프로젝트 창에서 ‘flutter_app

오른쪽 상단에 표시된 4가지 링크 중

4

>

test

>

pubspec.yaml’을 선택하고,

‘Flutter doctor’를 클릭하는 겁니다. 출력 결과는

5

하단 ‘Flutter’ 창에서 확인할 수 있습니다. 4

3

5

▶ flutter doctor 명령 실행

이 방법은 플러터 SDK를 환경 변수에 추가하지 않아도 작동하므로 편리합니다. 또한 flutter doctor --verbose 옵션이 붙은 명령이 수행되어 좀 더 자세한 결과를 보여줍니다.

오른쪽 상단에 표시된 4가지 링크의 역할은 다음과 같습니다.

040

1부 플러터에 입문하기


• Packages get : 외부 라이브러리를 추가한 후 프로젝트에 다운로드하여 적용합니다. • Packages upgrade : 외부 라이브러리 버전 등을 변경한 후 반영합니다. • Flutter upgrade : 플러터 SDK의 버전을 업그레이드합니다. • Flutter doctor : 플러터 환경 설정이 잘되었는지 검사합니다.

화면 하단 ‘Flutter’ 창의 출력 내용을 하나씩 살펴봅시다. 정보는 개발 환경에 따라 조금씩 다 르게 표시될 수 있습니다. 1 [✓] Flutter (Channel stable, v1.12.13+hotfix.5, on Mac OS X 10.15.1 19B88, locale ko-KR) 2 [✓] Android Studio (version 3.5) 3 [!] Android toolchain - develop for Android devices (Android SDK version 27.0.3)

✗ Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses 6 [✓] Xcode - develop for iOS and macOS (Xcode 11.2.1) 6 [✓] IntelliJ IDEA Ultimate Edition (version 2019.1.3.) 6 [✓] VS Code (version 1.40.1) 7 [!] Connected device

! No devices available

1

플러터 SDK의 설정 정보입니다. ✓ 마크는 정상, ! 마크는 경고, ✗ 마크는 설정이 안 되

어 있다는 것을 의미합니다.

2

안드로이드 스튜디오의 버전 정보입니다.

3

안드로이드 개발

을 위한 SDK 설정 정보입니다. 최초에는 이 부분에서 ‘Android license not accepted’라는 에러 메시지가 표시되고 명령어를 입력하도록 가이드하고 있습니다. doctor --android-licenses 명령을 입력한 후

설치가 된 것을 확인합니다.

6

5

4

터미널에서 flutter

다시 flutter doctor 명령을 실행하여 정상

Xcode, 인텔리제이, 비주얼 스튜디오 코드가 설치되어 있다

면 이러한 툴들의 설치 정보도 함께 표시됩니다.

7

연결된 기기나 에뮬레이터가 있는지에 대

한 정보입니다. 아직 연결된 기기가 없기 때문에 경고가 표시됩니다.

1.2 안드로이드용 프로젝트 이 책에서는 안드로이드용 프로젝트를 기본으로 설명합니다. 생성한 프로젝트에는 기본 샘플 코드가 작성되어 있습니다. 앱을 실행하려면 에뮬레이터 또는 실제 기기가 필요하기 때문에 안 드로이드용 에뮬레이터 또는 기기 연결을 준비합니다.

1장 생애 첫 모바일 앱 생성하기

041


1.2.1 에뮬레이터로 실행 플러터로 작성한 앱을 실행시키려면 가상의 기기인 에뮬레이터 또는 실제 기기를 연결해 야 합니다. 먼저 에뮬레이터를 생성합시다. 안드로이드 스튜디오 상단 툴바에서

1

‘AVD

Manager’를 클릭합니다. AVD Manager는 안드로이드 에뮬레이터 생성을 도와주는 도구입 니다.

1

▶ AVD Manager

AVD Manager를 실행하면 다음과 같은 화면이 표시됩니다. 새로운 가상 기기를 작성하기 위 해

2

‘Create Virtual Device’를 클릭합니다.

2

▶ Create Virtual Device

3

‘Phone’ 카테고리를 선택합니다. 가상 기기로

토어가 지원되는( 5

‘Pixel 2’를 선택합니다. 참고로 플레이스

표시가 있는) 모델을 선택해야 에뮬레이터가 플레이스토어에 설치됩니다.

‘Next’를 클릭합니다.

042

4

1부 플러터에 입문하기


2장 다트 문법 2.1 다트 언어 연습 환경

2.2 기본 문법 2.3 함수 2.4 분기와 반복 2.5 객체 지향 프로그래밍 2.6 컬렉션 2.7 함수형 프로그래밍 2.8 기타 유용한 기법 2.9 마치며


플러터 개발에는 다트 언어를 사용합니다. 이 책에서는 플러터 앱 개발에 꼭 필요한 기본 문법 과 핵심 문법을 설명합니다. 더 자세한 내용은 다트 온라인 매뉴얼에서 확인할 수 있습니다. •다트 문법 온라인 매뉴얼 : dart.dev/guides/language/language -tour

2.1 다트 언어 연습 환경 이미 다트 문법을 안다면 2장을 건너뛰고 3장부터 학습해도 됩니다. 2장에서 다트 문법을 열심 히 다루지만, 다트를 완전 정복하는 목적의 책이 아니므로 한 번 보는 것만으로는 완벽하게 문법 을 익히지 못할 겁니다. 어떤 언어든 눈으로 보는 것만으로는 코딩을 익힐 수 없으므로 플러터로 앱을 개발하면서 자연스럽게 익혀나가기 바랍니다. 이미 여러 개발 환경을 설치했습니다. 그래서 이번에는 개발 도구를 추가로 설치하지 않고 다트 패드 웹사이트를 활용하겠습니다. 다음 URL로 접속하면 온라인에서 다트 코드를 실행할 수 있 습니다. •dartpad.dev

▶ 웹 브라우저에서 다트 문법 연습하기

060

1부 플러터에 입문하기


다트 문법은 main ( ) 함수가 진입점 entry point 입니다. 이 장에서 설명하는 코드 대부분은 main ( ) 함수를 분량을 줄이는 차원에서 삭제했습니다. 따라서 실습을 할 때는 예제 코드를 main ( ) 함 수 내부에 작성해 이용하면 됩니다. void main() { // 여기에 작성합니다. print("Hello, World!"); }

2.2 기본 문법 주석, 변수, 상수, 연산자 사용법을 알아봅시다.

2.2.1 주석 주석은 코드에 달아두는 설명으로 실행에 영향을 주지 않습니다. 주석을 작성하는 방법은 아래 예시와 같이 총 3가지입니다. // 이것은 주석 /** * 이것도 주석 **/ /// 이것도 주석 void something() {}

• //

: 한 줄 주석

• /* ... */ : 여러 줄 주석 • ///

: 문서 주석

///를 메서드나 클래스 정의 위에 작성하면 dartdoc과 같은 문서 생성 도구를 통해 문서를 자

동으로 생성해줍니다. • dart.dev/tools/dartdoc

2장 다트 문법

061


2.2.2 문장 문장 statement 은 명령 단위입니다. 문장 끝은 세미콜론(; )으로 표시합니다(세미콜론 누락은 흔 히 발생하는 실수입니다. 문장 끝에 세미콜론을 꼭 챙겨주세요). void main() { // 여기에 작성합니다. print("Hello, World!")

// 에러!!

print('안녕하세요'); }

2.2.3 변수 변수는 데이터(값)를 담는 상자입니다. 변수 종류를 타입 type 또는 자료형이라고 합니다. 다트는 숫자나 문자열 같은 기본 변수 타입을 제공하며, 사용자가 직접 타입을 정의할 수도 있습니다.

'Sword'

8

문자열 타입

int 타입

▶ 문자열을 담는 문자열 타입과 숫자를 담는 int 타입

다트는 다음과 같은 기본 타입을 제공합니다. • int : 정수 • double : 실수(소수점) • String : 문자열 • bool : 참 또는 거짓 값을 갖는 타입(불리언 타입이라고 읽음)

변수명 앞에 타입을 선언하고, 변수명 뒤에 = 기호로 값을 할당합니다. 각 변수의 타입에 맞는 값을 할당해야 합니다. 즉, int 타입에 문자열 타입을 할당하면 안 됩니다. 문자열 타입은 다음과 같이 선언하고 값을 할당합니다. String name;

// 변수 선언

name = '홍길동'; // 값 할당

062

1부 플러터에 입문하기


문자열 묶음 기호로 작은따옴표와 큰따옴표 모두를 사용할 수 있습니다(문법 스타일 표준 가 이드에는 작은따옴표가 표준으로 되어 있습니다). String name;

// 변수 선언

name = "홍길동"; // 값 할당

bool 타입은 값으로 true와 false를 갖습니다.

bool b = true;

// 참(거짓은 false)

bool b2 = i < 10;

// i는 10보다 작다.

bool b3 = s.isEmpty;

끝으로 int와 double 타입 사용법도 확인합니다. int i = 10;

// 정수 10

double d = 10.0; // 실수 10.0

그런데 int와 double은 num 타입에 포함됩니다. 그래서 다음과 같이 사용할 수 있습니다. num a = 10; num b = 20.0;

num int

double

▶ num과 int, double의 포함 관계

일부 언어에서 더 큰 자료형인 double 타입에 int 타입을 대입하는 자동 형변환을 지원하기도 하지만 다트에서는 지원하지 않습니다. int a = 10; double b = a;

// 에러

2장 다트 문법

063


반면 num 타입에는 int와 double 타입 모두 대입할 수 있습니다. int a = 10; double b = 20.0; num c = a;

// ok

c = b;

// ok

변수에 담긴 값은 언제라도 다른 값으로 바꿀 수 있습니다. 값을 재할당한다고 표현합니다. String s = 'hello'; s = 'world';

2.2.4 타입 추론 다트는 타입을 직접 명시하지 않고 var로 대체할 수 있는 타입 추론을 지원합니다. 일반적으로 는 이 방법을 주로 사용합니다. var i = 10;

// int 타입

var d = 10.0;

// double 타입

var s = 'hello';

// 문자열 타입

var s2 = "hello";

// 문자열 타입

var b = true;

// 불리언 타입

var b2 = i < 10;

// 불리언 타입

var b3 = s.isEmpty; // 불리언 타입

2.2.5 상수 final, const 변수는 값이 변경되어 의도치 않게 에러를 발생할 가능성이 있으므로 가급적이면 값이 변하지 않게 상수로 사용하는 것이 좋습니다. 선언할 때 final 키워드를 제일 앞에 붙이면 값이 수정되 지 않는 상수로 사용할 수 있습니다. final String name = '홍길동'; name = '임꺽정';

064

// 에러

1부 플러터에 입문하기


타입을 생략하고 다음과 같이 짧게 작성할 수 있습니다. final name = '홍길동';

2.2.6 산술 연산자 다트에서는 다음과 같은 산술 연산자를 제공합니다. • + : 더하기 • - : 빼기 • * : 곱하기 • / : 나누기(double 타입 반환) • ~/ : 몫(int 타입 반환) • % : 나머지(int 타입 반환)

assert ( ) 함수는 계산 결과가 참인지 검사합니다. 다음 코드는 모두 결과가 참( true )입니다.

assert(2 + 3 = = 5); assert(5 - 2 = = 3); assert(3 * 5 = = 15); assert(5 / 2 = = 2.5); assert(5 ~/ 2 = = 2); assert(5 % 2 = = 1);

참고로 dartpad.dev 같은 웹에서는 assert ( ) 함수가 동작하지 않습니다. 더하기 연산자의 또 다른 쓰임새는 두 개의 문자열을 결합하는 겁니다. assert('hello' + ' world' = = 'hello world');

2.2.7 증감 연산자 증감 연산자는 값을 1씩 증가하거나 감소시키는 연산자로 후위 연산과 전위 연산이 있습니다. • 후위 연산 : [식]++, [식]-- (예 : a++, a-- ) • 전위 연산 : ++[식], --[식] (예 : ++a, --a )

2장 다트 문법

065


먼저 계산을 하는지 나중에 계산을 하는지에 따라서 미묘하게 결과가 달라질 수 있습니다. var num = 0; print(num++);

// 나중에 계산하므로 0 출력

// num = 1이 됨 print(++num);

// 먼저 계산하므로 2 출력

// num = 2가 됨

2.2.8 비교 연산자 다트에서는 다음과 같은 비교 연산자를 제공합니다. • == : 같다 • != : 다르다 • > : 더 크다 • < : 더 작다 • >= : 크거나 같다 • <= : 작거나 같다

다음 코드는 모두 결과가 참(true )입니다. assert(2 = = 2); assert(2 != 3); assert(3 > 2); assert(2 < 3); assert(3 >= 3); assert(2 <= 3);

2.2.9 논리 연산자 계산식을 연산하여 결과를 참 또는 거짓으로 반환하는 논리 연산자는 다음과 같습니다. • && : 그리고 • || : 또는 • = = : 같다 • ! : 부정 • != : 다르다

066

1부 플러터에 입문하기


다음은 논리 연산자를 사용한 예입니다. print(true && true);

// true

print(true && false);

// false

print(false && false);

// false

print(true || true);

// true

print(true || false);

// true

print(false || false);

// false

print(true = = true);

// true

print(true = = false);

// false

print(false = = false); // true print(true != true);

// false

print(true != false);

// true

print(false != false); // false

2.2.10 타입 검사(is, is! 키워드) 타입을 검사하는 키워드는 다음과 같습니다. • is : 같은 타입이면 true • is! : 다른 타입이면 true

int a = 10; if (a is int) { print('정수'); } String text = 'hello'; if (text is! int) { print('숫자가 아님'); }

2.2.11 형변환(as 키워드) 형변환 type casting 에는 as 키워드를 사용합니다. 다른 타입끼리는 변환이 안 되고 더 상위 개념으 로 변환할 수 있습니다.

2장 다트 문법

067


int와 double은 모두 num을 구현하는 타입이지만 서로는 관계가 없기 때문에 형변환이 불가능

합니다. var c = 30.5; int d = c as int;

// 에러

하지만 int와 double 모두 상위 개념인 num으로 형변환할 수 있습니다. dynamic d = 30.5; num n = d;

// as num; 생략 가능

2.3 함수 함수 function 는 특별한 코드 묶음 단위입니다. 플러터로 개발할 때는 다트에서 제공하는 다양한 함수를 사용하게 됩니다. 다트의 함수를 알아보겠습니다.

2.3.1 함수 형태 함수는 다음과 같은 형태로 작성합니다. 값을 반환할 때는 return 키워드를 사용합니다. 입력 받는 문자를 매개변수 parameter 라고 부르고 반환되는 값을 반환값이라고 합니다. int f(int x) { return x + 10; }

위 함수의 함수명은 f, 매개변수는 int 타입 x, 반환값은 int 타입입니다. ‘f 함수는 int 타입의 매개변수 x를 받고 x + 10을 int 타입으로 반환(return )하는 함수다’라고 말할 수 있습니다. 함수를 사용할 때는 다음과 같이 합니다. 반환값이 있으므로 다른 변수에 반환된 결과를 할당할 수 있습니다. 함수를 사용할 때 실제 입력하는 값을 인수 argument 라고 합니다. void main() { var result = f(10); } 068

1부 플러터에 입문하기


위 코드는 ‘f 함수에 10이라는 인수를 전달하여 반환된 결과를 result 변수에 대입했다’고 말할 수 있습니다. 함수는 입력과 출력을 다양하게 조합할 수 있습니다. 입력값은 없거나 여럿일 수 있습니다. 출력 값은 없거나 하나만 있을 수 있습니다. 다음은 매개변수가 둘인 함수입니다. int f(int x, int z) { return x + z + 10; }

다음은 매개변수가 없는 함수입니다. 이 함수는 ‘안녕하세요’라는 문자열을 반환합니다. String f() { return '안녕하세요'; }

함수가 꼭 값을 반환할 필요는 없습니다. 다음은 반환하는 값이 없는 함수의 예입니다. 함수명 앞에 있는 void는 반환값이 없다는 키워드입니다. void f(int x) { print(x); }

반환 타입으로는 모든 타입과 void를 지정할 수 있습니다. 반환 타입 역시 타입 추론에 의해 생 략할 수 있습니다. void greeting(String greet) { print('hello $greet'); } // 위 코드와 동일함 greeting(String greet) { print('hello $greet'); }

2장 다트 문법

069


print ( ) 함수는 반환값이 void인 대표적인 함수입니다. print ( ) 함수는 원하는 형태의 메시

지를 출력하고 싶을 때 사용하며, 문자열이나 변수에 담긴 값을 출력합니다. String _name = '홍길동'; print('Hello'), print(_name),

변수 앞에 $ 기호를 붙여 문자열 내에 변수를 삽입할 수 있습니다. 또한 $ 기호 뒤에 {}로 둘러 싸 수식을 포함한 각종 표현식을 사용할 수 있습니다. String _name = '홍길동'; int _age = 20; void main() { print('$_name은 $_age살입니다.'); print('$_name은 ${_name.length} 글자입니다.'); print('10년 후에는 ${_age + 10}살입니다.'); }

2.3.2 함수와 메서드 클래스 밖에 작성하는 함수를 최상위 함수라고 합니다. 클래스는 객체를 표현하는 방법으로

2.5절 ‘객체 지향 프로그래밍’에서 다룹니다. 최상위 함수(main 메서드처럼 가장 바깥에 작성 한 함수)는 어디에서나 호출할 수 있는 함수이며 이 책에서 함수라고 칭하는 대부분은 이러한 최상위 함수를 가리킵니다. // 최상위 함수 bool isEven(int number) { return number % 2 = = 0; } void main() { print(isEven(10)); }

070

1부 플러터에 입문하기


3장 프로젝트 구조와 앱 구조 3.1 프로젝트 구조 이해

3.2 샘플 앱 분석하기 3.3 실습 3.4 마치며


이 장에서는 프로젝트 구조와 앱 구조를 알아봅니다. 앱 구조는 3.2절에서 샘플 앱을 분석하고 간단한 실습을 하며 알아볼 겁니다. 안드로이드 스튜디오를 구동하고 하나하나 살피며 책을 따 라하기 바랍니다. 이 장에서 다루는 내용은 다음과 같습니다. •프로젝트 구조 이해 •샘플 앱 분석하기 •간단한 실습

3.1 프로젝트 구조 이해 플러터 앱을 잘 만들려면 먼저 프로젝트를 구성하는 폴더와 파일 역할을 알아야 합니다. 1장에 서 생성한 flutter_app을 기준으로 간단히 살펴보겠습니다. 다음은 프로젝트 창입니다. 크게

1

프로젝트를 구성하는 폴더

구분해서 알아보겠습니다.

1

2

▶ 프로젝트 창

프로젝트를 구성하는 폴더는 다음과 같습니다. •.idea : 개발 도구에 필요한 설정 •android : 안드로이드 네이티브 코드를 작성하는 부분 •build : 빌드시 생성되는 파일

100

1부 플러터에 입문하기

2

프로젝트를 구성하는 파일로


• ios : iOS 네이티브 코드를 작성하는 부분 • lib : 다트 코드를 작성하는 부분 • test : 테스트 코드를 작성하는 부분

프로젝트를 구성하는 파일은 다음과 같습니다. • .gitignore : Git 설정 파일. 버전 관리시 무시할 파일 규칙 작성 • .metadata : 프로젝트가 관리하는 파일. 임의로 수정하지 않습니다. • .packages : 각종 패키지 정보. 임의로 수정하지 않습니다. • flutter_app.iml : 개발 도구에 필요한 설정 파일. 임의로 수정하지 않습니다. • pubspec.lock : 패키지 매니저가 이용하는 파일. 임의로 수정하지 않습니다. • pubspec.yaml : 패키지 매니저가 이용하는 파일 • README.md : 프로젝트 설명을 작성하는 파일

.gitignore, pubspec.yaml, README.md 파일을 제외한 나머지 파일은 임의로 수정하면 안 됩니다.

3.2 샘플 앱 분석하기 프로젝트를 새로 작성하면 샘플 앱이 표시됩니다. 프로젝트 창의 lib 폴더에서 main.dart 파 일을 클릭하면 전체 코드를 볼 수 있습니다. 아래 코드는 원래 있던 주석을 제거하고 별도의 주 석으로 대체했습니다. import 'package:flutter/material.dart'; // 앱 시작 부분 void main() = > runApp(MyApp()); // 시작 클래스. 머티리얼 디자인 앱 생성 class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), 3장 프로젝트 구조와 앱 구조

101


home: MyHomePage(title: 'Flutter Demo Home Page'),

// 표시할 화면의 인스턴스

); } } // 시작 클래스가 실제로 표시하는 클래스. 카운터 앱 화면 class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() = > _MyHomePageState(); } // 위 MyHomePage 클래스의 상태를 나타내는 State 클래스 class _MyHomePageState extends State<MyHomePage> { int _counter = 0;

// 화면에 표시할 상탯값인 카운터 숫자

// counter 변수를 1 증가시키고 화면을 다시 그리는 메서드 void _incrementCounter() { setState(() {

// 화면을 다시 그리도록 하는 함수. StatefulWidget만 가능

_counter++; }); } // 화면에 UI를 그리는 메서드. 그려질 위젯을 반환 @override Widget build(BuildContext context) { return Scaffold(

// 머티리얼 디자인 기본 뼈대 위젯

appBar: AppBar( // 상단 앱바 title: Text(widget.title), ), body: Center(

// 표시할 내용

child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( 'You have pushed the button this many times:', ), Text( '$_counter',

// _counter 변수를 표시

style: Theme.of(context).textTheme.display1,

102

1부 플러터에 입문하기


), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter,

// 클릭 시 _incrementCounter() 메서드 실행

tooltip: 'Increment', child: Icon(Icons.add),

// 상단 앱바

), ); } }

샘플 앱을 실행해봅시다. 1

안드로이드 스튜디오를 실행합니다. 1장에서 만든 flutter_app 프로젝트가 기본으로 뜰 겁

니다. 2

‘AVD Manager’를 클릭해 에뮬레이터를 실행합니다.

3

‘Flutter Device Selection’에서 에뮬레이터를 선택합니다.

4

Shift + F10 혹은 Run ‘main.dart’ 버튼을 눌러 실행합니다.

샘플 앱은 + 버튼을 누르면 숫자가 증가하는 간단한 카운터 앱입니다.

▶ 카운터 앱 실행 화면 3장 프로젝트 구조와 앱 구조

103


3.2.1 앱 구조 카운터 앱의 코드를 분석하면서 플러터 동작 방식을 이해해봅시다. 앱의 전체 구조를 파악해볼 겁니다. 카운터 앱의 main.dart 파일은 여러 코드 덩어리로 구성되어 있습니다. import 'package:flutter/material.dart'; void main() = > runApp(MyApp()); class MyApp extends StatelessWidget { ...생략... } class MyHomePage extends StatefulWidget { ...생략... } class _MyHomePageState extends State<MyHomePage> { ...생략... }

위 세 덩어리는 사실상 거의 수정하지 않는 부분입니다. 그중 아래쪽 두 덩어리인 MyHomePage와 _MyHomePageState는 샘플 앱의 화면을 나타내는 코드입니다. 모든 코드는 사실상 마지막 덩어

리인 _MyHomePageState에 작성합니다.

3.2.2 앱 실행 부분 먼저 import 부분을 살펴봅니다. 플러터에서는 화면을 그리는 모든 디자인 요소를 위젯 widget 이 라고 합니다. package:flutter/material.dart 패키지에는 머티리얼 디자인 위젯들이 포함되 어 있습니다. 머티리얼 디자인을 기본으로 하는 앱은 이 패키지를 임포트하여 머티리얼 디자인 위젯을 사용할 수 있습니다. import 'package:flutter/material.dart';

main ( ) 함수는 앱의 시작점입니다. 여기서는 runApp ( ) 함수에 MyApp ( ) 인스턴스를 전달합

니다. 이 부분은 특별히 수정할 일이 없습니다. void main() = > runApp(MyApp());

104

1부 플러터에 입문하기


3.2.3 StatelessWidget 클래스 StatelessWidget 클래스는 상태가 없는 위젯을 정의하는 데 사용됩니다. runApp ( ) 함수에 전

달된 MyApp 클래스는 다음과 같이 정의되어 있습니다. class MyApp extends StatelessWidget {

1

@override Widget build(BuildContext context) { return MaterialApp(...생략...);

2

} }

MyApp 클래스는 StatelessWidget 클래스의 서브클래스입니다. StatelessWidget 클래스는 상

태 State 를 가지지 않는 위젯을 구성하는 기본 클래스입니다. 여기서 상태를 가지지 않는다는 것 은 한 번 그려진 후 다시 그리지 않는 경우이며, 이러한 클래스는 프로퍼티로 변수를 가지지 않 습니다(상수는 가질 수 있습니다). StatelessWidget 클래스는 build ( ) 메서드를 가지고 있습니다. build ( ) 메서드는 위젯을 생

성할 때 호출되는데, 실제로 화면에 그릴 위젯을 작성해 반환합니다. 따라서

1

StatelessWidget 클래스를 상속받은 MyApp 클래스는

2

MaterialApp 클래스의 인

스턴스를 작성해 반환합니다.

3.2.4 MaterialApp 클래스 build ( ) 메서드가 반환하는 MaterialApp 클래스는 다음과 같습니다. 여기까지는 거의 모든 프

로젝트에서 같습니다. return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Flutter Demo Home Page'), );

3장 프로젝트 구조와 앱 구조

105


사실 한 줄짜리 코드지만 보기 좋게 개행해서 여러 줄 코드처럼 보입니다. 여기서는 title, theme, home 세 가지 이름이 있는 인수를 설정합니다. 이 프로퍼티들을 설정하여 위젯의 속성을

표현합니다. title은 말 그대로 제목을 나타냅니다. theme는 테마를 지정합니다. 여기서는 파랑 계열의 색상

테마가 기본으로 설정되어 있습니다. home에 작성하는 위젯이 실제 이 앱이 표시하는 위젯이 됩 니다. NOTE _ 이름 있는 인수

다트 언어에는 이름 있는 인수와 이름 없는 인수(일반 인수)가 있습니다. 위젯에 따라 각각 사용 방법이 다릅 니다. • 이름 있는 인수는 인수 앞에 인수명을 씁니다. 예) MyHomePage (title: ‘hello’) • 이름 없는 인수는 다른 여타 언어와 같이 인수명을 쓰지 않습니다. 예) Text (‘hello’) 플러터에서 이름 있는 인수는 클래스의 프로퍼티에 값을 할당하는 것이며, 그 모양새는 클래스의 속성을 의 미합니다.

3.2.5 StatefulWidget 클래스 상태가 있는 위젯을 정의할 때는 StatefulWidget 클래스를 사용합니다. StatefulWidget 클래 스는 StatefulWidget을 상속받은 MyHomePage 클래스와 State<MyHomePage> 클래스를 상속받 은 _MyHomePageState 클래스로 구성됩니다. 샘플 앱은 다음과 같은 형태로 작성되어 있습니다. class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key);

1

final String title; @override _MyHomePageState createState() = > _MyHomePageState(); }

106

1부 플러터에 입문하기

2


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

// 변경 가능한 상태

3

Widget build(BuildContext context) {

4

...생략... @override return Scaffold(...생략...) } }

1

MyHomePage 클래스의 생성자는 key와 title 프로퍼티를 옵션으로 받아서 super 키워드로

부모 클래스의 생성자에 key를 전달합니다. 2

MyHomePage 클래스에는 상속받은 createState ( ) 메서드를 재정의하여 _MyHomePageState

클래스의 인스턴스를 반환합니다. 이 메서드는 StatefulWidget이 생성될 때 한 번만 실행되 는 메서드입니다. 3

State 클래스를 상속받은 클래스를 상태 클래스라고 부릅니다. 상태 클래스는 변경 가능한

상태를 프로퍼티 변수로 표현합니다. 나중에 이 변수의 값을 변경하면서 화면을 다시 그리게 됩니다. 4

_MyHomePageState 클래스의 상태에 따라 화면에 그려질 코드를 여기에 작성합니다. 모양새

는 StatelessWidget 클래스와 똑같습니다. build ( ) 메서드를 가지고 있고 여기에 화면에 그 려질 부분을 정의합니다.

3.2.6 위젯에서 위젯으로 값 전달 위젯에서 위젯으로 값을 전달하는 과정을 살펴봅시다. MaterialApp 클래스에서 home 프로퍼 티에 MyHomePage 인스턴스를 (생성하고) 인수로 전달하며, 그와 동시에 MyHomePage의 title 인숫값으로 ‘Flutter Demo Home Page’를 전달했습니다. ...생략... return MaterialApp( title: 'Flutter Demo', theme: ThemeData(

3장 프로젝트 구조와 앱 구조

107


primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Flutter Demo Home Page'), ); ...생략...

이렇게 전달받은 title 인숫값은 MyHomePage 클래스의 생성자의 this.title 매개변수로 전달 되어 필드 상수인 String title에 대입됩니다. class MyHomePage extends StatefulWidget { // 생성자 MyHomePage({Key key, this.title}) : super(key: key); final String title; ...생략... } // 상태 클래스 class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title),

1

), ); } }

이렇게 위젯 사이의 데이터 전달은 생성자를 활용합니다. 상태 클래스에서 StatefulWidget 클 래스에 접근하려면

1

widget 프로퍼티를 사용합니다.

3.2.7 상태 변경 State 클래스에는 주로 상태를 저장할 변수들과 그 변수를 조작할 메서드를 작성합니다. 카운

터 앱의 State 클래스는 다음과 같이 정의되어 있습니다.

108

1부 플러터에 입문하기


4장 기본 위젯 I 4.1 예제를 연습하는 방법 .

4.2 화면 배치에 쓰는 기본 위젯

.

4.3 위치, 정렬, 크기를 위한 위젯 4.4 버튼 계열 위젯 4.5 화면 표시용 위젯 4.6 마치며


화면을 구성하는 컴포넌트를 위젯이라고 부릅니다. 화면을 구성하려면 다양한 위젯을 조합해야 하므로 가능하면 많은 위젯을 아는 것이 좋습니다. 이 장에서는 자주 사용하는 위젯을 알아보겠 습니다. 더 많은 위젯을 만나고 싶다면 공식 웹사이트를 참고하기 바랍니다. • f lutter.dev/docs/development/ui/widgets

이 장에서 다루는 내용은 다음과 같습니다. • 위젯 사용 방법 연습하기 • 다양한 머티리얼 위젯 사용 방법

4.1 예제를 연습하는 방법 앱을 만들려면 기본 위젯 Widget 을 알아야 합니다. UI를 위젯의 조합으로 구성하기 때문입니다. 플러터는 머티리얼 디자인을 표준 디자인으로 채용하고, 필요에 따라서 iOS 쿠퍼티노 디자인 도 사용할 수 있습니다. 그리고 다양한 화면 크기에 대응하는 방법을 제공합니다.

4.1.1 실습 환경 소개 안드로이드 스튜디오에서 예제를 작성해 실행하면서 이 장을 익힙시다. 기존 샘플 예제의

main.dart 파일을 다음과 같이 수정합니다. MyApp 클래스까지는 공통 코드이며 수정하지 않 기 때문에 예시 코드에서는 생략합니다. 주로 으로 합니다. import 'package:flutter/material.dart'; void main() = > runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp(

122

1부 플러터에 입문하기

1

body 프로퍼티의 내용을 수정하는 것을 기본


title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(), ); } } // 여기까지는 공통 코드입니다. // 여기부터 수정합니다. class MyHomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('제목'), ), body: Text('여기에 예제 작성'),

// 주로 여기에 코딩합니다.

1

); } }

4.1.2 그 외 임시 실습 환경 소개 코드는 안드로이드 스튜디오에서 작성하는 것이 기본입니다. 하지만 급하게 무언가 시험해보 고 싶을 때는 웹 서비스를 이용하는 것도 좋습니다. 다트패드는 2장에서 이미 다트 연습용 도 구로 소개했습니다. •dartpad .dev

다트패드에서는 다트 언어뿐만 아니라 플러터 코드도 실행할 수 있습니다. 다트패드 웹사이트 에 접속한 뒤

1

‘New Pad’를 클릭합니다. 1

▶ New Pad 클릭

4장 기본 위젯 I

123


무슨 연습을 할지 선택하는 다이얼로그가 표시되는데

2

‘Flutter’를 선택하고

3

‘CREATE’를

클릭합니다.

2

3

▶ Flutter > CREATE

플러터로 작성된 ‘Hello World’가 표시됩니다. 오른쪽에는 여러 가지

4

샘플이 준비되어 있

으니 하나씩 체험해보기 바랍니다. 샘플 중에는 3장에서 살펴본 기본 샘플 앱인 카운터도 준비 되어 있습니다. 4

▶ 다트패드에서 플러터 코드도 간단히 실행 가능!

4.1.3 플러터 스튜디오 그 밖에 비주얼 에디터인 플러터 스튜디오 flutter studio 를 이용하면 드래그&드롭으로 위젯을 간단 히 시험할 수 있습니다. 대신 코드 수정은 불가능합니다.

124

1부 플러터에 입문하기


• f lutterstudio.app

▶ flutter studio 화면

위젯을 드래그&드롭하여 화면에 배치하고

1

‘{ }souce code’를 누르면 소스 코드를 바로 확

인할 수 있습니다.

1

▶ 소스 확인

4장 기본 위젯 I

125


4.2 화면 배치에 쓰는 기본 위젯 위젯 중에는 화면을 구성하고 배치하는 데 뼈대가 되는 것이 있습니다. 화면 배치에 사용되는 기본 위젯을 간단히 알아봅시다.

4.2.1 Container 아무것도 없는 위젯입니다. 다양한 프로퍼티를 가지고 있기 때문에 사용하기에 따라서 다양한 응용이 가능합니다. 자주 사용되는 위젯입니다.

가로와 세로 길이, 색, 안쪽 여백( padding ), 바깥쪽 여백( margin ) 등의 설정이 가능하고 child 프로퍼티로 또 다른 위젯을 자식으로 가질 수 있습니다.

4.1.1절 ‘실습 환경 소개’에서 안내한 기본 코드에서 Scaffold의 body 프로퍼티에 다음 코드를 작성합니다. Container( color: Colors.red, width: 100, height: 100, padding: const EdgeInsets.all(8.0), margin: const EdgeInsets.all(8.0), ) 126

1부 플러터에 입문하기


다음과 같이 빨간색 영역에 코드를 작성하면 됩니다.

4.2.2 Column 수직 방향으로 위젯들을 나란히 배치하는 위젯입니다. 레이아웃은 대부분 Column과 Row를 조합 하여 만들기 때문에 매우 자주 사용됩니다.

4장 기본 위젯 I

127


children 프로퍼티에는 여러 위젯의 리스트를 지정할 수 있습니다. 지정한 위젯들은 세로로 배

치됩니다. Column( children: <Widget>[ [위젯], [위젯], [위젯], ], ),

그럼 수직 방향으로 빨강, 초록, 파란색 박스를 나열해보겠습니다. Column( children: <Widget>[ Container( color: Colors.red, width: 100, height: 100, padding: const EdgeInsets.all(8.0), margin: const EdgeInsets.all(8.0), ), Container( color: Colors.green, width: 100, height: 100, padding: const EdgeInsets.all(8.0), margin: const EdgeInsets.all(8.0), ), Container( color: Colors.blue, width: 100, height: 100, padding: const EdgeInsets.all(8.0), margin: const EdgeInsets.all(8.0), ), ], ),

128

1부 플러터에 입문하기


4.2.3 Row Column과 반대로 수평 방향으로 위젯들을 나란히 배치하는 위젯입니다.

Column과 같이 children 프로퍼티에 여러 위젯을 나열합니다. Row, Column과 같이 방향성이 있

는 위젯은 mainAxis와 crossAxis 관련 프로퍼티가 있습니다. Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[ [위젯], [위젯], [위젯], ], ),

그럼 수평 방향으로 빨강, 초록, 파란색 박스를 나열해보겠습니다. Row( mainAxisSize: MainAxisSize.max,

// 가로로 꽉 채우기

mainAxisAlignment: MainAxisAlignment.center,

// 가로 방향으로 가운데 정렬하기

4장 기본 위젯 I

129


crossAxisAlignment: CrossAxisAlignment.center,

// 세로 방향으로 가운데 정렬하기

children: <Widget>[ Container( color: Colors.red, width: 100, height: 100, padding: const EdgeInsets.all(8.0), margin: const EdgeInsets.all(8.0), ), Container( color: Colors.green, width: 100, height: 100, padding: const EdgeInsets.all(8.0), margin: const EdgeInsets.all(8.0), ), Container( color: Colors.blue, width: 100, height: 100, padding: const EdgeInsets.all(8.0), margin: const EdgeInsets.all(8.0), ), ], ),

mainAxis는 위젯의 기본 방향을 나타냅니다. Row는 오른쪽, Column은 아래쪽이 mainAxis가

됩니다. crossAxis는 기본 방향의 반대 방향을 나타냅니다. Row는 아래쪽, Column은 오른쪽이 crossAxis가 됩니다. MainAxis CrossAxis

CrossAxis MainAxis

Row

▶ Row와 Column에서 mainAxis와 crossAxis

130

1부 플러터에 입문하기

Column


5장 기본 위젯 II 5.1 입력용 위젯

5.2 다이얼로그 5.3 이벤트 5.4 애니메이션 5.5 쿠퍼티노 디자인 5.6 마치며

4장 기본 위젯 I

159


화면을 구성하는 용도 외에도 사용자와 상호작용하거나 애니메이션을 구현하는 위젯도 있습니 다. 그리고 iOS 스타일의 쿠퍼티노 위젯도 별도로 준비되어 있습니다. 이 장에서 다루는 내용은 다음과 같습니다. •입력용 위젯 •다이얼로그 •이벤트 •애니메이션 •쿠퍼티노 디자인

5.1 입력용 위젯 플러터에는 많은 입력용 위젯이 있습니다. 여기서는 자주 사용되는 입력용 위젯 사용 방법을 알 아봅니다.

5.1.1 TextField 글자를 입력받는 위젯입니다. InputDecoration 클래스와 함께 사용하면 힌트 메시지나 외곽선 등의 꾸밈 효과를 간단히 추가할 수 있습니다.

1 2 3

1

160

밑줄만 표현하는 기본 형태입니다. 1부 플러터에 입문하기


TextField()

decoration 프로퍼티를 활용하면 다양한 효과를 줄 수 있습니다. 여기서는 InputDecoration

2

클래스의 labelText 프로퍼티를 활용하여 힌트를 표현하고 있습니다. TextField( decoration: InputDecoration( labelText: '여기에 입력하세요',

// 힌트

), ),

InputDecoration 클래스의 border 프로퍼티에 OutlineInputBorder 클래스의 인스턴스를

3

지정하면 외곽선과 힌트를 표현하는 머티리얼 디자인을 구현할 수 있습니다. TextField( decoration: InputDecoration( border: OutlineInputBorder(),

// 외곽선

labelText: '여기에 입력하세요', ), )

5.1.2 CheckBox와 Switch 설정 화면 등에 많이 사용되는 체크박스, 라디오 버튼, 스위치를 표현하는 위젯입니다.

5장 기본 위젯 II

161


Checkbox와 Switch는 모양만 다를 뿐 사용 방법은 동일합니다.

var isChecked = false; 1

Checkbox( value: isChecked,

2

onChanged: (value) {

3

setState(() { isChecked = value; } }, ), Switch( value: isChecked, onChanged: (value) { setState(() { isChecked = value; } }, ),

상태를 나타낼 불리언 타입의 변수가 필요하고

1

value 프로퍼티에 설정합니다. onChanged

2

이벤트는 체크값이 변할 때마다 발생하는데 여기서

3

변경된 값이 불리언 value 인수로 넘어오

며 setState ( ) 함수를 통해 value 프로퍼티에 지정한 변숫값을 변경하며 UI를 다시 그립니다. 앞의 그림대로 구현하면 다음과 같습니다. 상태를 나타내는 변수가 등장하므로 StatefulWidget 이어야 합니다. _isChecked 변수와 Checkbox와 Switch 관련 부분의 위치를 확인하세요. 관련 코드를 볼드체로 표시했습니다. class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() = > _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { var _isChecked = false;

162

1부 플러터에 입문하기


@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Checkbox / Radio / Switch'), ), body: Padding( padding: const EdgeInsets.all(8.0), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Checkbox( value: _isChecked, onChanged: (value) { setState(() { _isChecked = value; }); }, ), SizedBox( height: 40, ), Switch( value: _isChecked, onChanged: (value) { setState(() { _isChecked = value; }); }, ), ], ), ), ), ); } }

지금부터는 StatefulWidget을 만들 때 State 클래스만 표시하도록 하겠습니다.

5장 기본 위젯 II

163


5.1.3 Radio와 RadioListTile 선택 그룹 중 하나를 선택할 때 사용하는 위젯입니다. 어디까지를 터치 영역으로 볼 것이냐에 따 라서 Radio를 사용하거나 RadioListTile을 사용하는 두 가지 방법을 소개합니다.

Radio는 그룹 내에서 하나만 선택할 때 사용합니다. 그룹이 되는 항목을

정의하고

2

groupValue 프로퍼티에 열거형으로 정의한 Gender 타입의

1 3

열거형(enum )으로 변수를 지정하고,

onChanged 이벤트에서 변경된 값을 반영합니다. ListTile 대신 RadioListTile을 사용하면 가

로 전체가 터치 영역이 됩니다. enum Gender { MAN, WOMEN }

1

Gender _gender = Gender.MAN;

3

...생략... // Radio는 라디오 영역만 터치 영역으로 인식 ListTile( title: Text('남자'), leading: Radio( value: Gender.MAN, groupValue: _gender, onChanged: (value) {

164

1부 플러터에 입문하기

2


setState(() { _gender = value; }); }, ), ), ListTile( title: Text('여자'), leading: Radio( value: Gender.WOMEN, groupValue: _gender, onChanged: (value) { setState(() { _gender = value; }); }, ), ),

앞의 그림처럼 ListTile과 RadioListTile을 사용해보겠습니다. 열거형 Gender의 위치는 클래 스와 동일한 레벨로 작성하면 됩니다. enum Gender { MAN, WOMEN } class _MyHomePageState extends State<MyHomePage> { Gender _gender = Gender.MAN; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Radio / RadioListTile'), ), body: Padding( padding: const EdgeInsets.all(8.0), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,

5장 기본 위젯 II

165


children: <Widget>[ ListTile( title: Text('남자'), leading: Radio( value: Gender.MAN, groupValue: _gender, onChanged: (value) { setState(() { _gender = value; }); }, ), ), ListTile( title: Text('여자'), leading: Radio( value: Gender.WOMEN, groupValue: _gender, onChanged: (value) { setState(() { _gender = value; }); }, ), ), SizedBox( height: 40, ), RadioListTile( title: Text('남자'), value: Gender.MAN, groupValue: _gender, onChanged: (value) { setState(() { _gender = value; }); }, ), RadioListTile( title: Text('여자'), value: Gender.WOMEN,

166

1부 플러터에 입문하기


groupValue: _gender, onChanged: (value) { setState(() { _gender = value; }); }, ), ], ), ), ), ); } }

5.1.4 DropDownButton 여러 아이템 중 하나를 고를 수 있는 콤보박스 형태의 위젯입니다.

value 프로퍼티에 표시할 값을 지정합니다. items 프로퍼티에는 표시할 항목을 DropdownMenu Item 클래스의 인스턴스들을 담은 리스트로 지정해야 합니다. 상태를 가지므로 StatefulWidget

으로 작성합니다. 반복되는 코드는 생략했습니다.

5장 기본 위젯 II

167


// State 클래스 필드에 작성 final _valueList = ['첫 번째', '두 번째', '세 번째']; var _selectedValue = '첫 번째'; ...생략... // Scaffold의 body에 작성 DropdownButton( value: _selectedValue, items: _valueList.map(

1

(value) { return DropdownMenuItem( value: value, child: Text(value), ); }, ).toList(),

2

onChanged: (value) { setState(() { _selectedValue = value; }); }, ),

여기서는

1

map ( ) 함수를 사용하여 _valueList 리스트의 문자열 3개를 DropdownMenuItem

인스턴스 3개로 변환했습니다. 그리고

2

toList ( ) 함수를 사용하여 다시 리스트로 변환시켜

items 프로퍼티에 이 리스트를 지정했습니다. map ( ) 함수를 사용하여 값 리스트를 위젯 리스

트로 변환하는 코드가 자주 사용됩니다.

5.2 다이얼로그 다이얼로그는 사용자의 확인을 요구하거나 메시지를 표시하는 용도로 자주 사용합니다. 자주 사용되는 다이얼로그 작성 방법을 알아보겠습니다.

5.2.1 AlertDialog 머티리얼 디자인의 유저 확인용 다이얼로그입니다.

168

1부 플러터에 입문하기


AlertDialog를 표시하려면 showDialog ( ) 함수의 builder 프로퍼티에 AlertDialog 클래스

의 인스턴스를 반환하는 함수를 작성하면 됩니다. showDialog ( ) 함수의 barrierDismissible 프로퍼티는 다이얼로그 바깥 부분을 탭(터치)해도 닫히게 할 것인지 정합니다. showDialog( context: context, barrierDismissible: false,

// 사용자가 다이얼로그 바깥을 터치하면 닫히지 않음

builder: (BuildContext context) { return AlertDialog( title: Text('제목'),

1

content: SingleChildScrollView( child: ListBody(

2

4

children: <Widget>[ Text('Alert Dialog입니다'), Text('OK를 눌러 닫습니다'), ], ), ), actions: <Widget>[

3

FlatButton( child: Text('OK'), onPressed: () { // 다이얼로그 닫기 Navigator.of(context).pop();

5장 기본 위젯 II

169


}, ), FlatButton( child: Text('Cancel'), onPressed: () { // 다이얼로그 닫기 Navigator.of(context).pop(); }, ), ], ); }, );

AlertDialog 클래스는

그대로 제목 영역이며, 와 3

4

1 2

title과

2

content,

3

actions 영역을 정의해줍니다.

content는 내용 영역입니다. 여기서는

2

1

title은 말

SingleChildScrollView

ListBody 클래스를 사용하여 ListView와 동일한 효과를 가지도록 했습니다.

actions 프로퍼티에는 버튼들을 정의합니다. 여기서는 FlatButton 두 개를 정의했고 각 버

튼을 클릭할 때 Navigator.of (context ).pop ( )을 호출하여 다이얼로그를 닫습니다. 화면 전 환을 담당하는 Navigator 클래스는 6장에서 다룹니다.

5.2.2 DatePicker 날짜를 선택할 때 사용합니다.

170

1부 플러터에 입문하기


6장 내비게이션 6.1 새로운 화면으로 이동 .

6.2 routes를 활용한 내비게이션

.

6.3 내비게이션 동작 방식의 이해 6.4 마치며


새로운 화면으로 전환하거나 이전 화면으로 돌아가는 것을 내비게이션이라고 합니다. 이 장에서 는 플러터에서 제공하는 다양한 내비게이션 방법을 설명합니다. 이 장에서 다루는 내용은 다음과 같습니다. • 새로운 화면으로 이동하는 방법 • 이전 화면으로 돌아가는 방법 • 데이터를 다른 화면으로 전달하는 방법 • StatefulWidget 클래스의 내비게이션 방식과 생명주기 메서드

6.1 새로운 화면으로 이동 새로운 화면을 띄우거나 이전 화면으로 돌아가는 방법을 알아보겠습니다. 두 화면을 내비게이션 하는 앱을 만들어보겠습니다. main.dart 파일에 다음과 같이 두 화면에 해당하는 FirstPage와 SecondPage 클래스를 작성합니다.

import 'package:flutter/material.dart'; void main() = > runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: FirstPage(),

// 첫 페이지를 시작 페이지로 지정

); } } // 첫 페이지 class FirstPage extends StatelessWidget { @override

194

1부 플러터에 입문하기


Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('First'), ), body: RaisedButton( child: Text('다음 페이지로'), onPressed: () {}, ), ); } } // 두 번째 페이지 class SecondPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Second'), ), body: RaisedButton( child: Text('이전 페이지로'), onPressed: () {}, ), ); } }

각 화면에는 RaisedButton이 하나씩 있고 이 버튼을 눌렀을 때 화면 전환이 되도록 수정할 겁 니다.

6.1.1 파일 분할 및 임포트 방법 파일 하나에 모든 클래스를 작성할 수 있습니다. 예를 들어 main.dart 안에 여러 페이지를 작 성하면 다음과 같이 파일 하나만 사용합니다. lib main.dart

6장 내비게이션

195


물론 다음과 같이 별도 파일로 분리하여 작성할 수도 있습니다. lib main.dart first_page.dart second_page.dart

이처럼 파일을 분리할 경우에는

1

임포트하여 다른 파일에 있는 클래스를 사용할 수 있습니다.

import 'package:flutter/material.dart'; import 'package:flutter_basic/first_page.dart';

1

import 'package:flutter_basic/second_page.dart'; void main() = > runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: FirstPage(), ); } }

실제 프로그램을 작성할 때는 코드를 여러 파일에 분리하는 것이 코드 재활용 등의 면에서 좋 지만, 책에서는 편의상 모든 예제를 하나의 파일 안에 작성합니다.

6.1.2 push로 새로운 화면 호출 FirstPage 클래스를 수정하여 SecondPage로 전환하려면 Navigator 클래스의 push ( ) 메서드

를 사용합니다. 기본적인 사용 방법은 다음과 같습니다. Navigator.push( context, MaterialPageRoute(builder: (context) = > [이동할 페이지]), );

196

1부 플러터에 입문하기


첫 번째 인수로 context가 필요하고 두 번째 인수로 MaterialPageRoute 인스턴스가 필요합니 다. 이 클래스는 머티리얼 디자인으로 작성된 페이지 사이에 화면 전환을 할 때 사용됩니다. 이 클래스의 builder 프로퍼티에 이동할 페이지를 나타내는 함수를 작성합니다. 예를 들면 다음 과 같은 람다 함수를 전달할 수 있습니다. 입력 매개변수인 BuildContext 타입은 타입 추론에 의해 생략이 가능합니다. (Context context) = > SecondPage()

다음과 같이 FirstPage의 버튼을 눌렀을 때

1

SecondPage로 이동하는 코드를 Navigator.

push ( ) 메서드를 사용하여 작성할 수 있습니다.

class FirstPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('First'), ), body: RaisedButton( child: Text('다음 페이지로'), onPressed: () { Navigator.push(

// SecondPage로 화면 이동 코드

1

context, MaterialPageRoute(builder: (context) = > SecondPage()),

2

); }, ), ); } }

1

Navigator.push ( ) 메서드의 두 번째 인수로 사용된

2

MaterialPageRoute 클래스는 안드로

이드와 iOS 각 플랫폼에 맞는 화면 전환을 지원해줍니다. builder 프로퍼티에는 BuildContext 인스턴스를 인수로 받고 이동할 화면의 클래스 인스턴스를 반환하는 함수를 작성합니다. 여기서 는 SecondPage 화면을 표시합니다.

6장 내비게이션

197


예제를 실행하고 첫 번째 페이지에서

3

‘다음 페이지로’ 버튼을 탭하면 두 번째 페이지가 표시

됩니다. 게다가 별다른 코드를 추가하지 않아도 두 번째 페이지에는 AppBar의

4

leading 영역

에 뒤로 가기 아이콘이 표시되며 이 아이콘을 탭하면 이전 화면으로 이동하도록 자동으로 구성 됩니다. 4

3

▶ 머티리얼 디자인에 맞게 자동으로 뒤로 가기 아이콘도 생깁니다.

6.1.3 pop으로 이전 화면으로 이동 Navigator.push ( ) 메서드로 새로운 화면이 표시되어도 이전 화면은 메모리에 남게 됩니다.

이때 Navigator.pop ( ) 메서드로 현재 화면을 종료하고 이전 화면으로 돌아갈 수 있습니다. SecondPage 클래스의 코드를

1

다음과 같이 수정하면 버튼을 눌렀을 때 이전 화면이 다시 표

시됩니다. class SecondPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Second'), ), body: RaisedButton(

198

1부 플러터에 입문하기


child: Text('이전 페이지로'), onPressed: () { Navigator.pop(context);

// 현재 화면을 종료하고 이전 화면으로 돌아가기

1

}, ), ); } }

6.1.4 새로운 화면에 값 전달하기 새로운 화면을 표시하면서 데이터도 함께 전달하는 방법을 알아보겠습니다. 이름과 나이 프로퍼 티를 가지는 Person 클래스를 다음과 같이 정의해보았습니다. class Person { String name; int age; Person(this.name, this.age); } class FirstPage extends StatelessWidget { ...생략... } class SecondPage extends StatelessWidget { ...생략... }

그런 다음 FirstPage 클래스의 버튼 클릭 이벤트 부분을 다음처럼 수정합니다. onPressed: () { final person = Person('홍길동', 20); Navigator.push( context, MaterialPageRoute(builder: (context) = > SecondPage(person: person)), ); },

SecondPage 클래스에서 Person 객체를 받을 수 있도록 다음과 같이 코드를 수정합니다.

6장 내비게이션

199


class SecondPage extends StatelessWidget { final Person person; SecondPage({@required this.person});

1

@override Widget build(BuildContext context) { return ...생략... } }

1

@required를 붙이면 필수 입력 인수를 나타냅니다. SecondPage 클래스의 생성자는 Person

객체를 반드시 받아야 합니다.

6.1.5 이전 화면으로 데이터 돌려주기 Navigator.push ( ) 메서드와 Navigator.pop ( ) 메서드를 조금 수정하면 SecondPage 클래스

에서 FirstPage 클래스로 데이터를 돌려줄 수 있습니다. 다음 코드는 ok라는 문자열을 이전 페이지에 돌려줍니다. Navigator.pop(context, 'ok');

FirstPage 클래스가 SecondPage 클래스로부터 데이터를 돌려받으려면 push ( ) 메서드를 다음

과 같이 수정합니다. onPressed: () async {

2

final person = Person('홍길동', 20); final result = awaitNavigator.push(

1, 3

context, MaterialPageRoute(builder: (context) = > SecondPage(person: person)), ); print(result);

4

},

200

1부 플러터에 입문하기


7장 복잡한 UI 작성 7.1 해법 요약

7.2 스텝 1 : 뼈대 작성

7.3 스텝 2 : BottomNavigationBar 위젯을 이용한 하단 탭 구성 7.4 스텝 3 : AppBar 위젯 수정 7.5 스텝 4 : 화면이 3개인 UI 작성 7.6 생산성을 높여주는 단축키 7.7 스텝 5 : 상단 부분 7.8 스텝 6 : 중단 부분 7.9 스텝 7 : 하단 부분 7.10 마치며

6장 내비게이션

209


프로젝트 소개

난이도

★☆☆

프로젝트명

chapter07

핵심 구성 요소

- BottomNavigationBar : 하단의 탭을 구성합니다. - AppBar : 상단의 제목줄을 구성합니다. - Row, Column : 가로, 세로로 레이아웃을 구성합니다. - GestureDetector : 어떤 위젯이라도 클릭 가능하게 해줍니다. - Opacity : 투명도를 부여합니다. - CarouselSlider : 좌우로 슬라이드되는 UI 작성시 사용하는 별도의 라이브러리

210

1부 플러터에 입문하기


7.1 해법 요약 이 장에서는 다양한 위젯을 활용하여 실제로 자주 사용할 만한 UI를 작성합니다. 화면을 작성 하면서 장애를 극복하는 시나리오입니다. 이 장을 마치게 되면 어떤 UI를 맞닥뜨리더라도 당 황하지 않고 차근차근 만들어나갈 수 있는 요령과 팁을 배우게 됩니다. 이 장에서 다루는 내용은 다음과 같습니다. •플러터로 UI를 작성하는 요령과 팁 •다른 위젯으로 감싸거나 벗기는 팁 •라이브러리를 추가하고 사용하는 방법 •스크롤 안에 스크롤 객체를 넣을 때의 팁

작성할 화면은 다음과 같습니다. 하단에는 3개의 탭 메뉴가 있으며 클릭하면 다른 화면이 표시 됩니다. 화면을 크게 상단, 중단, 하단으로 나눕니다. 화면 전체는 상하로 스크롤됩니다. •상단 : 메뉴 7개가 있습니다. •중단 : 배너가 자동으로 좌우로 스크롤되는 슬라이더가 있습니다. •하단 : 게시글이 표시되는 리스트가 있습니다. •탭 메뉴 : 3개의 탭이 있습니다.

상단

중단

하단

탭 메뉴 ▶ 완성된 앱

7장 복잡한 UI 작성

211


구현 순서는 다음과 같습니다. 1. 스텝 1 : 뼈대 작성 2. 스텝 2 : BottomNavigationBar 위젯을 이용한 하단 탭 구성 3. 스텝 3 : AppBar 위젯 수정 4. 스텝 4 : 화면이 3개인 UI 작성 5. 스텝 5 : 상단 부분 6. 스텝 6 : 중단 부분 7. 스텝 7 : 하단 부분

7.2 스텝 1 : 뼈대 작성 새로 시작하는 마음으로 프로젝트의 main.dart 파일을 다음과 같이 백지 상태로 수정합니다. 수정된 부분은 볼드체로 표시했습니다. import 'package:flutter/material.dart'; void main() = > runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget {

1

@override _MyHomePageState createState() = > _MyHomePageState(); }

212

1부 플러터에 입문하기


class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return Container(); } }

1

MyHomePage, _MyHomePageState 클래스는 전부 타이핑하는 것이 아니라 3.3.3절 ‘코드 자동

완성 기능 이용하기’에서 배운 대로 stful 작성 후 엔터키를 눌러서 빠르게 작성합니다.

7.3 스텝 2 : BottomNavigationBar 위젯을 이용한 하단 탭 구성 총 3개 페이지로 구성된 UI 앱입니다. 탭을 클릭하면 페이지가 전환되도록 하단 탭 부분을 먼 저 작성하겠습니다. 머티리얼 디자인 앱의 뼈대인 Scaffold 위젯은 상단 제목이 표시되는 AppBar 위젯뿐만 아니라 하단 탭을 구성하는 BottomNavigationBar 위젯도 지원합니다. 하단에 3개 탭을 배치하려면 Scaffold 위젯의 bottomNavigationBar 프로퍼티에 BottomNavigationBar 인스턴스를 정의하

면 됩니다. BottomNavigationBar 위젯을 사용하여 다음과 같은 화면을 만들어보겠습니다.

▶ 앱을 실행하면 하단에 세 개의 탭이 있고 탭을 클릭하면 페이지가 전환됩니다.

7장 복잡한 UI 작성

213


7.3.1 하단 탭 작성 하단에 3개 탭을 표시하는 _MyHomePageState 클래스를 다음과 같이 작성합니다. class _MyHomePageState extends State<MyHomePage> { var _index = 0;

// 페이지 인덱스 0, 1, 2

1

@override Widget build(BuildContext context) { return Scaffold(

2

appBar: AppBar( title: Text('복잡한 UI'), ), body: Center( child: Text( '$_index 페이지', style: TextStyle(fontSize: 40), ), ), bottomNavigationBar: BottomNavigationBar( onTap: (index) {

3

4

setState(() { _index = index;

// 선택된 탭의 인덱스로 _index를 변경

}); }, currentIndex: _index,

// 선택된 인덱스

items: <BottomNavigationBarItem>[ BottomNavigationBarItem( title: Text('홈'), icon: Icon(Icons.home), ), BottomNavigationBarItem( title: Text('이용서비스'), icon: Icon(Icons.assignment), ), BottomNavigationBarItem( title: Text('내 정보'), icon: Icon(Icons.account_circle), ), ], ),

214

1부 플러터에 입문하기

6

5


); } }

1

3개 페이지를 표현할 수 있도록 _index 변수를 준비합니다. 각 페이지는 0, 1, 2 값을 가지

게 합니다. 2

build ( ) 메서드에 작성된 Container ( ) 코드를 Scaffold 위젯으로 수정했습니다. appBar

프로퍼티와 body 프로퍼티 작성은 지금까지와 비슷합니다. 3

bottomNavigationBar 프로퍼티에 탭을 3 개 작성했습니다.

6

items 프로퍼티에는

BottomNavigationBarItem 위젯의 리스트를 정의합니다. 이 위젯은 탭을 정의하고 title과 icon을 지정할 수 있습니다.

5

currentIndex 프로퍼티에는 현재 선택된 탭이 어떤 것인지 0

번부터 시작하는 인덱스 번호를 지정해줍니다. 4

탭을 클릭하면 onTap 이벤트가 동작하고 선택된 탭의 인덱스가 전달됩니다. 또한 currentIndex

에 설정된 _index 값을 새로 클릭한 탭의 인덱스로 교체한 후 setState ( ) 메서드를 사용해 화 면을 갱신합니다. 앱을 실행하여 하단의 3개 탭이 잘 표시되는지, 탭을 클릭하면 해당 인덱스의 페이지가 화면에 잘 표시되는지 확인합니다. 이러한 UI는 요즘 앱에서 자주 사용하는 디자인입니다.

7.4 스텝 3 : AppBar 위젯 수정 AppBar 위젯은 제목이나 메뉴를 표시하는 등 머티리얼 디자인에서 앱의 통일성을 위해 꼭 필요

한 요소입니다. AppBar 위젯에는 여러 가지 프로퍼티가 있어 입맛에 맞게 수정할 수 있습니다. Scaffold의 appBar 프로퍼티를 다음과 같이 수정합니다.

appBar: AppBar( backgroundColor: Colors.white,

// 배경색을 흰색으로

1

title: Text( '복잡한 UI', style: TextStyle(color: Colors.black),

// 글자색을 검은색으로

2

7장 복잡한 UI 작성

215


), centerTitle: true,

// 제목을 가운데로

3

),

▶ 제목이 가운데로 이동하고 색상이 변경됩니다.

1

backgroundColor 프로퍼티에 흰색을 지정하여 AppBar 위젯의 배경색을 변경합니다.

2

기본 테마의 제목은 흰색이 기본값이기 때문에 글자색을 검은색으로 변경해서 화면에 잘 보

이도록 합니다. Colors 클래스에는 다양한 색상값이 미리 상수로 정의되어 있어서 간단하게 색 상을 선택할 때 유용합니다. 3

안드로이드에서는 기본적으로 제목이 좌측으로 정렬됩니다. centerTitle 프로퍼티를 지정

하면 제목을 가운데에 표시할 수 있습니다. 실행하면 AppBar에 표시된 제목이 가운데로 이동하며, 배경색은 흰색으로, 글자색은 검은색으 로 변경됩니다. AppBar 위젯을 직접 수정하여 배경색과 글자색을 변경했지만 전체 테마 설정을 변경하면 더 간

단하게 동일한 효과를 얻을 수 있습니다.

216

1부 플러터에 입문하기


NOTE _ 전체 테마를 변경하는 방법

AppBar를 매번 수정하는 것보다 전체 앱의 테마를 수정하는 것이 더 편한 경우가 있습니다. MyApp 클래스의 build ( ) 메서드에 작성된 MaterialApp 클래스의 theme 프로퍼티에는 ThemeData 인스턴스가 정의되어

있습니다. 기존에 작성된 primarySwatch 프로퍼티 대신 primaryColor 프로퍼티에 흰색을 지정하는 것으 로 AppBar의 색상이나 글자색을 수정하지 않아도 간단히 동일한 효과를 얻을 수 있습니다. theme: ThemeData( primarySwatch: Colors.blue, primaryColor: Colors.white, ),

테마 수정에 대한 더 자세한 정보는 공식 문서에서 얻을 수 있습니다. • flutter.dev/docs/cookbook/design/themes

7.4.1 AppBar 오른쪽에 메뉴 추가 AppBar 위젯의 actions 프로퍼티에 위젯의 리스트를 정의하여 간단히 메뉴를 추가할 수 있습

니다. AppBar 위젯의 actions 프로퍼티를 다음과 같이 작성합니다.

appBar: AppBar( title: Text('복잡한 UI'), actions: <Widget>[ IconButton(

1

icon: Icon( Icons.add, color: Colors.black,

// 앱의 전체 테마를 수정했다면 작성하지 않아도 됨

2

), onPressed: () {}, ), ], ),

AppBar 위젯의 actions 프로퍼티에는 어떠한 위젯도 리스트로 배치할 수 있습니다.

일반적으로 AppBar 메뉴를 작성할 때는

1

IconButton 위젯을 사용합니다. IconButton 위젯은

icon과 onPressed 프로퍼티를 정의할 수 있습니다.

7장 복잡한 UI 작성

217


현재 테마의 설정은 AppBar의 글자나 아이콘 색이 흰색입니다. 그런데 AppBar의 배경색도 흰색 이므로 그 위에 표시할 글자나 아이콘 색을

2

검은색으로 바꿔야 잘 보이게 됩니다. 하지만 위

에서 소개한 전체 테마의 기본색을 흰색으로 설정했다면

2

코드를 작성할 필요가 없습니다.

▶ 앱바 오른쪽에 메뉴 추가

7.5 스텝 4 : 화면이 3개인 UI 작성 현재까지는 별도의 페이지를 작성하지 않고 _index 값만 변경하여 표시하고 있습니다. 이제 3 개 페이지를 작성하고 실제로 각 페이지가 표시되도록 코드를 수정해야 합니다.

main.dart 파일에 계속해서 다음과 같이 StatelessWidget 클래스를 상속받은 Page1, Page2, Page3 클래스를 정의합니다. 모든 페이지를 똑같은 형태로 만들고 Text의 글자만 ‘홈 페이지’,

‘이용서비스’, ‘내 정보’로 작성합니다. StatelessWidget 클래스는 stless 단축키를 사용하여 작성합니다. class Page1 extends StatelessWidget { @override Widget build(BuildContext context) { return Center(

218

1부 플러터에 입문하기


child: Text( '홈 페이지',

// 이 부분의 글자만 다르게 작성

style: TextStyle(fontSize: 40), ), ); } } class Page2 extends StatelessWidget {...생략...}

// 이용서비스

class Page3 extends StatelessWidget {...생략...}

// 내 정보

화면을 작성할 때는 상태를 변경할 만한 변수가 없다면 StatelessWidget으로 작성하도록 합 니다. 다음으로 Scaffold의 body 프로퍼티는 방금 작성한 페이지가 표시되도록 다음과 같이 코드를 수정합니다. class _MyHomePageState extends State<MyHomePage> { var _index = 0; var _pages = [

1

Page1(), Page2(), Page3(), ]; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(...생략...), body: _pages[_index],

2

bottomNavigationBar: BottomNavigationBar(...생략...); } }

1

페이지를 _pages 리스트 변수의 값으로 정의했습니다.

2

body 프로퍼티에는 화면이 갱신될 때마다 현재 선택된 인덱스 번호인 _index를 활용하여 해

당 페이지를 찾아내도록 했습니다.

7장 복잡한 UI 작성

219


▶ 작성한 페이지가 표시됩니다.

앱을 실행하면 추가한 페이지들이 표시됩니다.

7.6 생산성을 높여주는 단축키 플러터 코드로 UI를 작성할 때 한 번에 완벽한 코드를 만들 수 있는 사람은 거의 없습니다. 작업 하다 보면 Column이나 Row로 감싸거나 Padding으로 감싸는 경우가 빈번합니다. 그렇게 되면 나 중에 수동으로 Padding을 제거하거나 Column을 제거하는 일이 발생해 굉장히 불편합니다. 여러 위젯이 중첩된 코드 중간에 위젯을 추가하거나 삭제할 때 정확한 위치에 괄호를 넣거나 제거하 는 것이 얼마나 어려운 일인지 겪어보면 알게 됩니다. 지금부터 따라할 예제도 계속해서 다른 위젯으로 감싸는 일이 많습니다. 다행히 안드로이드 스 튜디오에서는 다른 위젯으로 감싸거나 벗기는 것을 쉽게 처리해주는 기능을 제공합니다.

7.6.1 현재 위젯을 벗겨내거나 다른 위젯으로 감싸기 다른 위젯으로 감싸고 싶은 위젯 코드 앞에 커서를 두고 Alt + Enter 를 누릅니다. Wrap

with XXX 형태로 메뉴가 표시되는데 XXX 위젯으로 감싸는 메뉴입니다. Center, Column,

220

1부 플러터에 입문하기


8장 비만도 계산기 8.1 해법 요약 .

8.2 준비하기 8.3 스텝 1 : 기본 코드 작성 8.4 스텝 2 : 키와 몸무게를 입력하는 화면 작성 8.5 스텝 3 : 결과 화면 작성 8.6 스텝 4 : 값 검증 및 화면 전환 8.7 스텝 5 : 결과 표시 8.8 마치며


앱 소개

난이도

★☆☆

프로젝트명

chapter08

기능

- 키와 몸무게를 입력하고 결과 버튼을 누르면 다른 화면에서 비만도 결과를 문자와 그림으로 보여줍니다. - 마지막에 입력한 키와 몸무게는 자동으로 저장됩니다.

핵심 구성 요소

- TextFormField : 입력 양식이 올바른지 검사 기능이 포함된 글자를 입력받는 위젯 - Form : 회원 가입 폼 같은 입력 양식을 감싸는 위젯. 예외 처리 등이 편리합니다. - RaisedButton : 일반 버튼 - Text : 결과 표시용 위젯 - Icon : 결과와 함께 보여줄 아이콘 - Navigator : 화면 전환용 클래스

244

2부 플러터로 앱 개발하기


8.1 해법 요약 지금까지 플러터의 전반적인 기능을 배웠습니다. 이제 어느 정도 플러터 코드 작성에 익숙해졌 다고 봐도 됩니다. 그럼 비교적 간단한 앱인 비만도 계산기를 만들어봅시다. 이 장에서 배우는 내용을 잘 활용한다면 회원 가입과 같은 입력 양식 폼을 플러터에서 어떻게 지원하는지 배울 수 있습니다. 앱에 대해 간단히 소개를 하자면 키와 몸무게를 입력받는 화면과 결과를 표시하는 화면이 필요 합니다. 첫 번째 화면에서 키와 몸무게를 입력받습니다. 이때 키 또는 몸무게를 입력하지 않고 결과 버 튼을 누르면 에러 메시지가 출력됩니다.

▶ 값을 입력하지 않으면 입력값을 검증하여 오류 메시지를 표시합니다.

키와 몸무게를 입력한 후 결과 버튼을 누르면 결과 화면이 표시됩니다. BMI Body Mess Index (체질 량지수) 계산 결과에 따라 세 가지 결과 중 하나가 표시됩니다.

8장 비만도 계산기

245


▶ 세 가지 결과 중 하나가 표시됩니다.

구현 순서는 다음과 같습니다. 1. 준비하기 : 새로 등장하는 개념 학습 2. 스텝 1 : 기본 코드 준비 3. 스텝 2 : 키와 몸무게를 입력하는 화면 작성 4. 스텝 3 : 결과 화면 작성 5. 스텝 4 : 값 검증 및 화면 전환 6. 스텝 5 : 결과 표시

8.2 준비하기 이 장에서 새로 등장하는 몇 가지 기능을 먼저 알아보겠습니다. 각 기능은 다음과 같은 클래스 를 활용합니다. •입력값 출력하기 : TextEditingController •폼의 입력값 검증하기 : Form , TextFormField

246

2부 플러터로 앱 개발하기


8.2.1 입력값 출력하기 사용자에게 값을 입력받을 때 사용하는 위젯이 TextField 위젯(또는 TextFormField 위젯. 이 하 TextField )입니다. TextEditingController 클래스의 인스턴스를 통해서 TextField 위젯 에 작성된 값을 얻을 수 있습니다. 다음은 TextEditingController 클래스를 사용하는 예입니 다. 이 예제는 TextField 위젯이 2개 있고 입력값이 변하면 각각 로그를 출력합니다. import 'package:flutter/material.dart'; void main() = > runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Retrieve Text Input', home: MyCustomForm(), ); } } class MyCustomForm extends StatefulWidget { @override _MyCustomFormState createState() = > _MyCustomFormState(); } class _MyCustomFormState extends State<MyCustomForm> { // TextField의 현잿값을 얻는 데 필요 final myController = TextEditingController();

1

@override void initState() { super.initState(); // addListener로 상태를 모니터링할 수 있음 myController.addListener(_printLatestValue);

4

}

8장 비만도 계산기

247


@override void dispose() { // 화면이 종료될 때는 반드시 위젯 트리에서 컨트롤러를 해제해야 함 myController.dispose();

2

super.dispose(); } _printLatestValue() {

5

// 컨트롤러의 text 프로퍼티로 연결된 TextField에 입력된 값을 얻음 print("두 번째 text field: ${myController.text}"); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Text Input 연습'), ), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: <Widget>[ TextField( onChanged: (text) {

// 텍스트 변경 감지 이벤트

6

print("첫 번째 text field: $text"); }, ), TextField( controller: myController,

// 컨트롤러를 지정

3

), ], ), ), ); } }

1

TextField 위젯 수에 맞게 TextEditingController 클래스의 인스턴스(이하 컨트롤러)를

준비합니다.

248

2부 플러터로 앱 개발하기


2

컨트롤러는 화면이 종료될 때 dispose ( ) 메서드로 반드시 해제해야 합니다.

3

TextField 위젯에서는 controller 프로퍼티에 컨트롤러 변수를 설정합니다. 이렇게 하면

myController 컨트롤러 변수를 통해서 TextField 인스턴스의 값을 얻거나 변경된 값을 모니

터링할 수 있습니다. 4

TextField 위젯의 값이 변경될 때마다 무언가를 수행하고 싶다면 addListener ( ) 메서드를

사용합니다. myController 컨트롤러 변수가 연결된 두 번째 TextField의 값이 변경될 때마다 _printLatestValue ( ) 메서드가 실행됩니다. 5

컨트롤러가 연결된 TextField 위젯에 입력된 값은 컨트롤러의 text 프로퍼티를 통해 얻을

수 있습니다. 6

TextField 위젯 자체의 값 변경을 모니터링하는 것은 onChanged 프로퍼티로도 간단히 구현

됩니다.

8.2.2 폼의 입력값 검증하기 Form과 TextFormField를 사용하면 회원 가입처럼 사용자 입력값을 검증해야 할 때 유용합니

다. 다음 코드는 버튼을 클릭하면 사용자가 입력한 값이 정해진 규칙에 맞는지 검사하는 예입 니다.

▶ 아무것도 입력하지 않으면 검증 에러, 값을 입력하면 검증 완료

8장 비만도 계산기

249


import 'package:flutter/material.dart'; void main() = > runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: '폼 검증 데모', home: Scaffold( appBar: AppBar( title: Text('폼 검증 데모'), ), body: MyCustomForm(), ), ); } } class MyCustomForm extends StatefulWidget { @override MyCustomFormState createState() { return MyCustomFormState(); } } class MyCustomFormState extends State<MyCustomForm> { // Form 위젯에 유니크한 키값을 부여하고 검증시 사용 final _formKey = GlobalKey<FormState>();

1

@override Widget build(BuildContext context) { // Form 위젯에 _formKey를 지정 return Form(

2

key: _formKey,

3

child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ TextFormField(

4

validator: (value) { if (value.isEmpty) {

250

2부 플러터로 앱 개발하기


return '글자를 입력하세요'; } return null; }, ), Padding( padding: const EdgeInsets.symmetric(vertical: 16.0), child: RaisedButton( onPressed: () { // 폼을 검증하여 통과하면 true, 실패하면 false 리턴 if (_formKey.currentState.validate()) {

5

// 검증이 통과하면 스낵바 표시 Scaffold.of(context) .showSnackBar(SnackBar(content: Text('검증 완료'))); } }, child: Text('검증'), ), ), ], ), ); } }

입력값을 검증하는 데는 Form과 TextFormField 위젯을 사용합니다. TextFormField 위젯은 TextField 위젯이 제공하는 기능에 추가로

4

validator 프로퍼티를 활용한 검증 기능도 제공

합니다. 검증에는 3

4

TextFormField 위젯을 사용하며, 검증할 내용 전체를

Form 위젯에는 유니크한(유일무이한) 키를 지정해야 하며

1

2

Form 위젯으로 감쌉니다.

GlobalKey<FromState> 인스

턴스를 키로 사용합니다. 4

TextFormFiled 위젯에는 validator 프로퍼티가 있으며 여기에는 입력된 값을 인수(value )

로 받는 함수를 작성합니다. 또한 검증 로직을 작성하는데, 에러 메시지를 문자열로 반환하거나 null을 반환하여 검증이 통과되었음을 정의할 수 있습니다. 5

폼의 검증은 _formKey.currentState.validate ( )로 수행하며 true 또는 false 값을 반환

합니다. 폼 안에 TextFormField 위젯이 여러 개 있어도 이 한 줄로 검증을 체크할 수 있습니다.

8장 비만도 계산기

251


SnackBar 클래스는 하단에 메시지를 표시하는 클래스입니다. 검증이 완료되면 ‘검증 완료’라는

메시지를 표시합니다.

8.3 스텝 1 : 기본 코드 작성 앱의 화면은 2개입니다. 기본 코드를 먼저 작성하고 세부 항목을 완성해나가겠습니다. 구현 순 서는 다음과 같습니다. • 첫 번째 페이지를 StatefulWidget으로 작성 • 두 번째 페이지를 StatelessWidget으로 작성

8.3.1 기본 코드 준비 프로젝트의 main.dart 파일이 다음과 같은 형태가 되도록 작성합니다. import 'package:flutter/material.dart'; void main() = > runApp(MyApp()); class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: BmiMain(), ); } } // 첫 번째 페이지(StatefulWidget)

1

class BmiMain extends StatefulWidget {...생략...} class _BmiMainState extends State<BmiMain> {...생략...}

252

2부 플러터로 앱 개발하기


9장 스톱워치 9.1 해법 요약

9.2 스텝 1 : UI 작성

.

9.3 스텝 2 : 타이머 구현하기 9.4 스텝 3 : 랩타임 기록하기 9.5 마치며

8장 비만도 계산기

267


앱 소개

난이도

★★☆

프로젝트명

chapter09

기능

- 타이머를 시작, 일시정지하고 초기화할 수 있습니다. - 타이머 실행 중에 랩타임을 측정하여 표시합니다.

핵심 구성 요소

268

- Timer : 일정 시간 간격으로 지정한 동작을 수행하게 하는 클래스

2부 플러터로 앱 개발하기


9.1 해법 요약 이 장에서는 달리기할 때 시간을 재고 랩타임을 측정하는 스톱워치를 만들어봅니다. 스톱워치는

0.01초까지 측정 가능해야 하며 Timer 클래스를 활용하여 0.01초마다 화면을 갱신합니다. 1

시작 버튼 : 시간 측정이 시작되며, 일시정지 아이콘으로 변경됩니다. 다시 누르면 일시정지

됩니다. 2

랩타임 : 현재 시간을 스크롤 영역에 추가합니다.

3

초기화 : 모든 것이 초기화됩니다.

시간

스크롤 영역

기록 2 초기화

1 시작/일시정지

3

▶ 각 영역의 기능 설명

9.2 스텝 1 : UI 작성 스톱워치의 UI는 크게 시간을 표시하는 Text 위젯 2개, 랩타임을 표시하는 ListView, 3개의 버튼으로 구성됩니다. 구현 순서는 다음과 같습니다. 1. 기본 코드 준비 2. 시작/일시정지 버튼 영역 UI 작성 3. 타이머 영역 UI 작성

9장 스톱워치

269


9.2.1 기본 코드 준비 스톱워치는 화면이 하나인 앱입니다. 그리고 화면에 표시되는 시간은 계속 변화하기 때문에 상 태가 있는 StatefulWidget으로 만듭니다. import 'package:flutter/material.dart'; void main() = > runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'StopWatch', theme: ThemeData( primarySwatch: Colors.blue, ), home: StopWatchPage(), ); } } class StopWatchPage extends StatefulWidget {...생략...} class _StopWatchPageState extends State<StopWatchPage> {...생략...}

9.2.2 시작/일시정지 버튼 영역 UI 작성 하단의 시작/일시정지 버튼이 위치하는 영역을 먼저 작성합니다.

▶ 시작/일시정지 버튼 영역

_StopWatchPageState 클래스의 build ( ) 메서드를 다음과 같이 수정하고 에러가 나지 않도록 _buildBody ( )와 _clickButton ( ) 메서드를 선언해둡니다.

270

2부 플러터로 앱 개발하기


Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('StopWatch'), ), body: _buildBody(),

// 이 메서드는 뒤에서 계속 작성합니다.

bottomNavigationBar: BottomAppBar(

1

child: Container( height: 50.0, ), ), floatingActionButton: FloatingActionButton(

2

onPressed: () = > setState(() { _clickButton();

3

}), child: Icon(Icons.play_arrow), ), floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,

4

); } // 내용 부분 Widget _buildBody() { return Container(); } // 시작 또는 일시정지 버튼 클릭 void _clickButton() { }

1

bottomNavigationBar 프로퍼티에는 어떤 위젯도 배치할 수 있으며, 여기서는 BottomAppBar

위젯을 배치했습니다. 내부에는 원하는 위젯을 배치할 수 있지만 여기서는 단순히 디자인 요소 로서 높이가 50인 빈 영역을 사용합니다. BottomAppBar 위젯은 말 그대로 하단에 배치하는 AppBar입니다. Scaffold 위젯의 bottomNavi gationBar 프로퍼티에 배치하는 것이 일반적이며 FloatingActionButton 위젯과도 자연스럽게

어울립니다. BottomAppBar 위젯 자체로는 아무것도 없는 빈 영역입니다. 일반적으로 하단 메뉴 와 FloatingActionButton 위젯을 함께 사용하는 경우에 사용됩니다.

9장 스톱워치

271


floatingActionButton 프로퍼티에는 시작 버튼이 위치합니다. 이 버튼을 클릭하면

2

3

_clickButton ( ) 메서드가 실행됩니다. 이 메서드의 내용은 뒤에서 완성합니다. floatingActionButtonLocation 프로퍼티에 FloatingActionButton 위젯의 위치를 가운

4

데로 지정했습니다. BottomAppBar 위젯은 FloatingActionButton 위젯과 함께 사용하면 자연 스럽게 어울립니다.

9.2.3 타이머 영역 UI 작성 타이머 영역을 완성해봅시다.

▶ 타이머 영역을 완성했을 때의 화면

타이머를 표시하는 _buildBody ( ) 메서드를 다음과 같이 수정합니다. 볼드체로 표시한 부분은 임시로 작성한 부분이며 앞으로 수정해야 하는 부분입니다. Widget _buildBody() { return Center( child: Padding( padding: const EdgeInsets.only(top: 30), child: Stack( children: <Widget>[ Column( children: <Widget>[

272

2부 플러터로 앱 개발하기


Row(

// 시간을 표시하는 영역

1

mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, children: <Widget>[ Text(

// 초

'0', style: TextStyle(fontSize: 50.0), ), Text('00'),

// 1/100초

], ), Container(

// 랩타임을 표시하는 영역

2

width: 100, height: 200, child: ListView( children: <Widget>[], ), ) ], ), Positioned(

3

left: 10, bottom: 10, child: FloatingActionButton(

// 왼쪽 아래에 위치한 초기화 버튼

backgroundColor: Colors.deepOrange, onPressed: () {}, child: Icon(Icons.rotate_left), ), ), Positioned(

4

right: 10, bottom: 10, child: RaisedButton(

// 오른쪽 아래에 위치한 랩타임 버튼

onPressed: () {}, child: Text('랩타임'), ), ) ], ), ), ); }

9장 스톱워치

273


시간을 초와 1/100초로 표시하는 영역입니다. Row 위젯에 Text 위젯 두 개를 배치했으며

1

하단 정렬하고 있습니다. 랩타임을 표시할 영역으로 가로 100, 세로 200 크기의 ListView 위젯을 배치했습니다. 크

2

기를 나타내는 위젯은 Container 위젯 대신 SizedBox 위젯으로 대체 가능합니다. 3

초기화 버튼입니다. 왼쪽 아래에 위치시키기 위해 Positioned 위젯으로 감쌌습니다.

4

랩타임 버튼입니다. 오른쪽 아래에 위치시키기 위해 Positioned 위젯으로 감쌌습니다.

Stack 위젯 내부에는 여러 위젯을 겹칠 수 있습니다. Positioned 위젯을 Stack 위젯의 children

프로퍼티에 사용할 수 있으며 자유롭게 위치도 정할 수 있습니다. 다음 코드는 가로, 세로 75 크기와 오른쪽 25, 아래쪽 50의 여백을 가지도록 위젯을 배치하는 예입니다. Stack(children: [ Positioned( bottom: 50, right: 25, width: 75, height: 75, child: [위젯], ), ])

Positioned 위젯의 생성자에 지정할 수 있는 프로퍼티는 다음과 같습니다. •left : 왼쪽 여백 •right : 오른쪽 여백 •top : 위쪽 여백 •bottom : 아래쪽 여백 •width : 가로 길이 •height : 세로 길이

274

2부 플러터로 앱 개발하기


9.3 스텝 2 : 타이머 구현하기 스톱워치의 타이머를 다음 순서대로 구현합니다. 1. Timer 클래스와 필요한 변수 준비 2. 시작/일시정지 상태 변환 로직 3. 시작/일시정지 동작 로직 4. 시간 표시 5. 시간을 표시하는 영역 UI 수정 6. 초기화

9.3.1 Timer 클래스 타이머 기능의 핵심인 Timer 클래스의 사용 방법을 간단히 알아보겠습니다. Timer 클래스는 dart:async 패키지에 포함된 클래스로 일정 간격 동안 반복하여 동작을 수행해야 할 때 사용하

는 클래스입니다. 다음 코드는 0.01초에 한 번씩 작업을 수행합니다. import 'dart:async'; ...생략... Timer.periodic(Duration(milliseconds: 10), (timer) { // 할 일 }

반복 실행 주기를 Timer.periodic ( ) 메서드의 첫 번째 인수 Duration 인스턴스에 설정하면 두 번째 인수로 받은 함수에서 실행되는 구조입니다. Duration 클래스는 주기를 정의합니다. Duration 클래스의 생성자에 지정할 수 있는 프로퍼티

는 다음과 같습니다. • days : 날짜 • hours : 시간 • minutes : 분 • seconds : 초 • milliseconds : 천 분의 1초 • microseconds : 백만 분의 1초

9장 스톱워치

275


예를 들어 다음 코드는 1시간 30분마다 한 번씩 실행됩니다. Duration(hours: 1, minutes: 30, (timer) { // 동작 })

9.3.2 Timer 클래스와 필요한 변수 준비 타이머 기능을 구현하기 위해서는 Timer 클래스가 필요합니다. Timer 클래스는 dart:async 패 키지를 임포트해야 사용할 수 있습니다. import 'dart:async';

_StopWatchPageState 클래스에는 스톱워치에 필요한 변수를 선언합니다.

class _StopWatchPageState extends State<StopWatchPage> { Timer _timer;

// 타이머

var _time = 0;

// 0.01초마다 1씩 증가시킬 정수형 변수

var _isRunning = false;

// 현재 시작 상태를 나타낼 불리언 변수

List<String> _lapTimes = [];

// 랩타임에 표시할 시간을 저장할 리스트

시간을 계산할 변수 _time, 타이머를 시작하거나 멈추기 위한 불리언 변수 _isRunning, 랩타임 에 표시할 문자열을 저장할 리스트 변수 _lapTimes를 준비했습니다. Timer 클래스는 앱을 종료할 때 반복되는 동작을 취소해야 합니다. dispose ( ) 메서드를 재정의

하여 타이머가 취소되도록 합니다. @override void dispose() { _timer?.cancel(); super.dispose(); }

276

2부 플러터로 앱 개발하기


10장 할 일 관리 10.1 해법 요약 . .

10.2 스텝 1 : 할 일 관리 앱 기본 버전 작성 10.3 스텝 2 : 파이어베이스 설정 10.4 스텝 3 : Firestore를 활용하여 기능 수정 10.5 마치며

9장 스톱워치

283


앱 소개

난이도

★★★

프로젝트명

chapter10

기능

- 할 일 추가 - 할 일 목록 표시 - 할 일 완료/미완료 - 할 일 삭제 - 모든 자료는 클라우드 DB인 Firestore에 저장

핵심 구성 요소

- 파이어베이스 : 서버의 다양한 기능을 복잡한 지식 없이 사용하도록 제공되는 서비스 - Firestore : 파이어베이스에서 제공하는 클라우드 DB 서비스

284

2부 플러터로 앱 개발하기


10.1 해법 요약 이 장에서 다룰 예제는 클라우드 데이터베이스(이하 DB )를 활용하는 할 일 관리 앱입니다. 기 능은 단순합니다. 할 일을 추가하고, 완료 표시하고, 삭제할 수 있습니다. 자료는 파이어베이스 라는 서비스가 제공하는 클라우드 DB인 Firestore에 저장합니다. 데이터베이스의 주요 기능을 한 단어로 요약하면 CRUD입니다. 데이터를 추가 Create 하고, 읽고 Read,

수정 Update 하고, 삭제 Delete 하는 겁니다. 여기에 원하는 데이터 가져오기 Query 까지 지원합

니다. 예제의 동작을 간단히 설명하겠습니다. 1

할 일을 입력하고

2

‘추가’ 버튼을 누르면

3

리스트에 할 일이 추가됩니다.

1 2 3

▶ 할 일 추가

리스트에 추가된 할 일 목록 중

4

완료하고 싶은 할 일 목록을 터치하면

5

취소선과 이탤릭체

로 변경됩니다. 다시 터치하면 원래대로 돌아갑니다.

10장 할 일 관리

285


4

5

▶ 할 일 완료

삭제하고 싶은 할 일 목록을

6

쓰레기통 아이콘을 클릭하여 삭제합니다.

6

▶ 할 일 삭제

구현 순서는 다음과 같습니다. 1. 스텝 1 : 할 일 관리 앱 기본 버전 작성 2. 스텝 2 : 파이어베이스 설정 3. 스텝 3 : Firestore를 활용하여 기능 수정

286

2부 플러터로 앱 개발하기


10.2 스텝 1 : 할 일 관리 앱 기본 버전 작성 이 예제는 먼저 클라우드 기능이 없는 할 일 관리 앱 코드를 작성하고 클라우드 DB로 기능을 수정해 나갑니다. 먼저 기본 버전을 작성합니다. 구현 순서는 다음과 같습니다. 1. 기본 코드 준비 2. 변수 준비 3. 전체 UI 작성 4. 할 일 목록 UI 작성 5. 전체 UI와 할 일 목록 UI 결합 6. 기능 작성 7. 기능과 UI 연결

10.2.1 기본 코드 준비 먼저 클라우드 기능이 없는 기본적인 ‘할 일 관리 앱’을 작성합니다. 프로젝트의 main.dart 파 일에 다음과 같이 기본 코드를 작성합니다. import 'package:flutter/material.dart'; void main() = > runApp(MyApp()); // 할 일 클래스

1

class Todo { bool isDone = false; String title; Todo(this.title); } // 시작 클래스 class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp(

10장 할 일 관리

287


title: '할 일 관리', theme: ThemeData( primarySwatch: Colors.blue, ), home: TodoListPage(), ); } } // TodoListPage 클래스

2

class TodoListPage extends StatefulWidget { @override _TodoListPageState createState() = > _TodoListPageState(); } // TodoListPage의 State 클래스 class _TodoListPageState extends State<TodoListPage> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('남은 할 일'), ), body: Container(); ); } }

1

이번 예제에서는 할 일 정보를 표현하기 위해 Todo 클래스를 작성했습니다. 완료 여부와 할

일 내용을 프로퍼티로 가지는 클래스입니다. 2

단축키 stful을 사용하여 앱의 화면을 StatefulWidget으로 작성하고 _TodoListPageState

클래스에는 기본적인 Scaffold만 작성해둡니다.

10.2.2 변수 준비 할 일 목록을 저장할 변수와 입력받은 할 일 문자열을 조작하는 컨트롤러를 준비하겠습니다. _TodoListPageState 클래스 상단에 다음과 같이 작성합니다.

288 2부 플러터로 앱 개발하기


// TodoListPage의 State 클래스 class _TodoListPageState extends State<TodoListPage> { // 할 일 목록을 저장할 리스트 final _items = <Todo>[];

1

// 할 일 문자열 조작을 위한 컨트롤러 var _todoController = TextEditingController();

2

@override void dispose() { _todoController.dispose();

// 사용이 끝나면 해제

3

super.dispose(); }

1

할 일 목록 리스트 작성시 <Todo>를 앞에 작성하여 Todo 객체를 담는 것을 명시했습니다.

2

할 일 문자열을 조작하기 위한 컨트롤러입니다.

3

컨트롤러는 사용이 끝나면 dispose ( ) 메서드로 해제해야 합니다.

10.2.3 전체 UI 작성 화면은 크게

1

할 일을 입력받는 TextField 위젯,

2

추가 버튼,

3

할 일 목록을 표시할

ListView로 구성됩니다.

1

2

3

▶ 화면 구성 10장 할 일 관리

289


_TodoListPageState 클래스의 build ( ) 메서드를 다음과 같이 수정합니다.

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('남은 할 일'), ), body: Padding( padding: const EdgeInsets.all(8.0), child: Column( children: <Widget>[ Row( children: <Widget>[ Expanded( child: TextField(

1

controller: _todoController, ), ), RaisedButton(

2

child: Text('추가'), onPressed: () {},

// 뒤에서 계속 작성

), ], ), Expanded( child: ListView(

3

children: <Widget>[],

// 뒤에서 계속 작성

), ), ], ), ), ); }

1

할 일을 입력받을 TextField입니다. 컨트롤러를 연결하고 Expanded 위젯으로 감싸서

가 버튼 이외의 영역을 꽉 채우게 됩니다.

290

2부 플러터로 앱 개발하기

2


2

추가 버튼의 동작은 아직 정의하지 않았습니다.

3

할 일 목록을 표시하는 부분입니다. ListView 위젯은 Column 위젯의 children 프로퍼티에

포함될 때 Expanded 위젯으로 감싸야 화면에 정상적으로 표시됩니다. children 프로퍼티는 아 직 정의하지 않았습니다.

10.2.4 할 일 목록 UI 작성 할 일 목록에 표시되는 아이템은 2

1

다음과 같은 형태를 가집니다. 목록의 아이템을 클릭하면

취소선과 이탤릭체가 적용됩니다.

1 2

▶ 할 일 목록 UI

_TodoListPageState 클래스에 다음과 같이 _buildItemWidget ( ) 메서드를 작성합니다.

// 할 일 객체를 ListTile 형태로 변경하는 메서드 Widget _buildItemWidget(Todo todo) {

1

return ListTile( onTap: () {},

// Todo : 클릭 시 완료/취소되도록 수정

title: Text( todo.title,

// 할 일

style: todo.isDone

// 완료일 때는 스타일 적용

2

? TextStyle(

10장 할 일 관리

291


decoration: TextDecoration.lineThrough, fontStyle: FontStyle.italic,

// 취소선

// 이탤릭체

) : null,

// 아무 스타일도 적용 안 함

), trailing: IconButton(

3

icon: Icon(Icons.delete_forever), onPressed: () {},

// Todo : 쓰레기통 클릭 시 삭제되도록 수정

), ); }

1

_buildItemWidget ( ) 메서드는 Todo 객체를 인수로 받고 ListTile 위젯을 반환합니다.

2

Todo 객체의 isDone 프로퍼티의 값에 따라 일반적인 Text가 사용되거나 취소선과 이탤릭체

가 적용된 Text가 사용됩니다.

3

trailing 프로퍼티에는 IconButton 위젯으로 쓰레기통 아이

콘을 배치했습니다.

10.2.5 전체 UI와 할 일 목록 UI 결합 작성한 할 일 목록 UI가 할 일 목록 ListView에 표시되도록 하겠습니다. build ( ) 메서드에서 남겨두었던 전체 UI에서 할 일 목록을 표시할 children 프로퍼티에 방금

작성한 할 일 목록 UI가 표시되도록 다음과 같이 수정합니다. Expanded( child: ListView( children: _items.map((todo) = > _buildItemWidget(todo)).toList(), ), ),

값 리스트를 위젯 리스트로 변환하는 코드입니다. _items 리스트의 항목을 map ( ) 함수를 통해 내부 순환하여 todo 인수로 받고 _buildItemWidget ( ) 메서드를 반환합니다. 이를 toList ( ) 함수로 다시 리스트로 변환합니다.

292

2부 플러터로 앱 개발하기


10.2.6 기능 작성 이 앱은 다음 세 가지 기능이 있습니다. • 할 일 추가 • 할 일 삭제 • 할 일 완료/미완료

각 기능을 Todo 객체를 인수로 받는 메서드로 작성하겠습니다. _TodoListPageState 클래스에 다음과 같이 메서드 3개를 작성합니다. // 할 일 추가 메서드 void _addTodo(Todo todo) { setState(() { _items.add(todo);

1

_todoController.text = '';

// 할 일 입력 필드를 비움

}); } // 할 일 삭제 메서드 void _deleteTodo(Todo todo) { setState(() { _items.remove(todo);

2

}); } // 할 일 완료/미완료 메서드 void _toggleTodo(Todo todo) { setState(() { todo.isDone = !todo.isDone;

3

}); }

메서드의 내용을 보면 아시겠지만 굉장히 단순합니다. _items 리스트에 Todo 객체를 거나

2

삭제하거나

3

1

추가하

isDone 프로퍼티값을 변경하고 setState ( ) 함수로 UI를 다시 그리는

메서드들입니다. 1

_addTodo ( ) 메서드에서는 할 일 목록에 새로운 Todo 객체를 추가하고 TextField에 입력한

글자를 지웁니다.

10장 할 일 관리

293


2

_deleteTodo ( ) 메서드에서는 할 일 목록에서 선택한 Todo 객체를 삭제합니다.

3

_toggleTodo ( ) 메서드에서는 Todo 객체의 isDone 값을 반전시킵니다( true면 false로,

false면 true로).

10.2.7 기능과 UI 연결 앞의 세 가지 메서드로 작성한 기능 3개를 각각 UI의 이벤트와 연결하도록 하겠습니다. 1

build ( ) 메서드에 작성된 추가 버튼을 클릭했을 때 _addTodo ( ) 메서드가 실행되도록 다음

과 같이 수정합니다. RaisedButton( child: Text('추가'), onPressed: () = > _addTodo(Todo(_todoController.text)), ),

할 일 목록 UI 인 _buildItemWidget ( ) 메서드에서 ListTile 위젯의 onTap 프로퍼티와 IconButton 위젯의 onPressed 프로퍼티를 수정하여 클릭했을 때 완료/미완료와 삭제 처리가

되도록 다음과 같이 수정합니다. // 할 일 객체를 ListTile 형태로 변경하는 메서드 Widget _buildItemWidget(Todo todo) { return ListTile( onTap: () = > _toggleTodo(todo),

// 완료/미완료

2

title: Text( todo.title, style: todo.isDone ? TextStyle( decoration: TextDecoration.lineThrough, fontStyle: FontStyle.italic, ) : null, ), trailing: IconButton( icon: Icon(Icons.delete_forever), onPressed: () = > _deleteTodo(todo),

294

2부 플러터로 앱 개발하기

// 삭제

3


), ); }

2

ListTile 위젯을 클릭하면 _toggleTodo ( ) 메서드를 실행하여 완료/미완료 상태가 변경됩

니다. 3

쓰레기통 아이콘을 클릭하면 _deleteTodo ( ) 메서드를 실행하여 항목이 삭제됩니다.

기본적인 할 일 관리 앱 작성이 끝났습니다. 작성한 예제를 실행하고 동작을 확인해보세요.

10.3 스텝 2 : 파이어베이스 설정 작성한 ‘할 일 관리’ 앱은 앱을 재시작하면 모든 자료가 사라집니다. 자료를 저장하려면 파일이 나 로컬 DB 또는 클라우드 DB 등에 자료를 보관해야 합니다. 우리는 구글 파이어베이스 Firebase 가 제공하는 클라우드 DB를 사용할 겁니다. 구현 순서는 다음과 같습니다. 1. 파이어베이스 연동하기 2. Firestore 설정

10.3.1 파이어베이스 연동하기 먼저 파이어베이스 웹사이트(firebase.google.com/)에 런 다음 첫 페이지에서

2

1

구글 계정으로 로그인합니다. 그

‘시작하기’ 버튼을 클릭합니다.

2

▶ 파이어베이스 웹사이트

10장 할 일 관리

295


그런 다음 화면에 보이는

3

‘프로젝트 만들기’ 버튼을 클릭합니다.

3

▶ 프로젝트 만들기

프로젝트명은 원하는 이름으로 작성하면 됩니다. 여기서는 5

‘Firebase 약관에 동의합니다.’를 체크하고

6

4

‘my todo list’를 입력했습니다.

‘계속’ 버튼을 클릭합니다.

4

5

6

▶ 프로젝트명 지정 후 약관 동의

다음 화면에 나오는 구글 애널리틱스는 이 책에서 다루는 범위를 벗어나므로 제하고

296

8

‘프로젝트 만들기’ 버튼을 클릭합니다.

2부 플러터로 앱 개발하기

7

사용 설정을 해


7

8

▶ 애널리틱스 설정 해제

프로젝트가 생성되고 나서 보이는 다음 화면에서

9

‘계속’ 버튼을 클릭합니다.

9

▶ 프로젝트 생성 완료 화면

10장 할 일 관리

297


그러면 다음 그림과 같은 파이어베이스 콘솔이 보입니다.

10

안드로이드 아이콘을 클릭하여 안

드로이드 앱을 추가해보겠습니다.

10

▶ 파이어베이스 콘솔에서 안드로이드 앱 추가

앱에 파이어베이스를 추가하려면 작성 중인 안드로이드 앱의 패키지명을 알아야 합니다. 안드 로이드 프로젝트의 환경 설정 파일에는 build.gradle 파일이 두 개 있습니다. 프로젝트 폴더 의 android/app 아래에 있는

11

build.gradle 파일을 열고 다음과 같이

12

applicationId

항목에 있는 값을 찾아서 클립보드에 복사(Ctrl + C )해둡니다. 이때 build.gradle 파일에 에러처럼 빨간줄이 표시될 수 있는데 안드로이드 스튜디오를 재시 작하면 빨간줄이 사라지고 build.gradle 파일을 열면 다시 생깁니다. 정상 동작이므로 무시하 기 바랍니다.

11

12

▶ 안드로이드 패키지명 복사

298

2부 플러터로 앱 개발하기


★★★★★★ ★ ★★

앱을 만드는 ‘완벽한 준비’에 시간을 낭비하지 마세요. 이 책은 기본을 빠르게 익히고 앱을 직접 만들며 필요한 기능을 알아가

유튜브, 블로그, 학원, 대학 등에서 이미 검증된 강의 본

는 ‘입문 + 활용서’로서 여러분의 시간을 아껴줍니다. ‘다트 언어 + 플러터 + 안드로이드 스튜디오 + 앱 개발’을 한 권으로 전

연의 장점을 극대화하고 더 체계화해 책으로 담았습니다.

달하므로, 다트(Dart) 언어와 플러터(Flutter)를 몰라도 빠르게 배워 앱을 만들 수 있습니다. 또한 입문자 눈높이에서 설명하며

입문자 눈높이에서 설명하고 작고 실용적인 프로젝트를

차츰 높은 난도의 앱을 완성해나가므로 초보자도 책을 완독할 수 있습니다. 이 책에서 제공하는 3가지 앱을 만들다 보면 플러

수행해 실전 능력을 키워줍니다. 빠르게 개발 능력을 배

터로 앱을 개발하는 데 필요한 실무 능력을 제대로 갖추게 될 겁니다.

우려는 입문자와 더 다양한 경험을 쌓으려는 기존 개발자 에게 유용합니다.

쉬워서

실용적이라서

시종일관 입문자 눈높이 설명

개념을 제시하면서도 완벽한 따라 하기 구현

실전에 유용한 3가지 실용 앱 개발

이 책에서 만들어보는 앱

추천사

비만도 계산기

■ 이

스톱워치

할 일 관리

책은 다트 언어와 위젯에 쉽게 익숙해지도록 구성되어 누구라도 앱을 만들 수 있게 해줍니다. 또한 저자가 검증

하고 실무에 사용하는 솔루션 코드로 가득해 입문자뿐 아니라 기존 앱 개발자에게도 ‘사이다’ 같은 책이 될 겁니다.

역시 플러터는 『오준석의 플러터 생존코딩』

한 번 코딩으로 안드로이드와 iOS 앱을 개발할 수 있는 플러터의 매력을 이 책과 함께 만끽하시기 바랍니다.

오준석 지음

초보자 중심이라서

플러터 생존코딩

이 시리즈는 단기간에 실무 능력을 갖추게 도와줍니다.

★★ ★ ★★

★★

★★

★★★★★★

★★ ★

★★★★★★

<소문난 명강의>시리즈 소개

오준석의

소문난 명강사 ‘오준석’이 안드로이드·iOS 앱 개발자에게 보내는 선물 같은 책

★★★★★★

★★ ★

소문난 명강의

★★★★★ ★★

★★★★★★

★★★★★

★★★★★★ ★ ★★

★★★★★ ★★

★★

소문난 명강의

★★★★★

★★

★ ★★ ★

★ ★★ ★

★★★★★★ 지은이_ 오준석 a811219@gmail.com

{

오준석의

플러터 생존코딩

문주현 블루애플 안드로이드 개발자

Flutter와 Dart 입문부터 안드로이드와 iOS용 3가지 앱 개발까지 오준석 지음

관련 도서

소문난 명강의 :

처음 배우는 플러터

오준석의 안드로이드 생존코딩

스위프트 프로그래밍 (3판)

예제 소스 github.com/junsuk5/flutter_basic

IT전문서 / 모바일 프로그래밍

정가 28,000원

{

교육하고 책 쓰는 개발자. 일본에서 개발자로 생활하다 2010년에 귀국해 안드로이드 앱을 개발합니다. 일본 테크시드, 토카이리카, LG전자 등에서 근무했습니다. 현재는 앱을 개발하고, 온라인 교육 플랫폼 인프런에서 온라인 강의를, 세민직업전문학교에서 오프라인 강의 를 합니다. 저서로 『소문난 명강의 : 오준석의 안드로이 드 생존코딩』(한빛미디어, 2018), 『될 때까지 안드로이 드』(루비페이퍼, 2018)가 있습니다.

유튜브 (안드로이드 생존코딩) youtube.com/c/안드로이드생존코딩 온라인 강의 플랫폼 survivalcoding.com


Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.