첫 Flutter 앱 작성하기 - 1부

첫 Flutter 앱을 만드는 방법을 안내합니다. 변수, 반복문, 조건문 등 기본 프로그래밍 개념과 객체지향에 친숙하다면, 이 튜토리얼을 완료할 수 있습니다. Dart 경험이나 모바일, 웹 프로그래밍 경험이 없어도 상관없습니다.
이 가이드는 코드랩 2부 중 1부입니다. 2부는 Google Developers에서 보실 수 있습니다. 1부 또한 Google Developers에서도 볼 수 있습니다.
1부에서 무엇을 만드는가
스타트업 회사를 위해 이름을 생성하여 제안하는 간단한 모바일 앱을 구현할 것입니다. 사용자는 이름을 선택하거나 선택을 취소할 수 있으며, 가장 좋은 이름을 저장할 수 있습니다. 코드는 lazy하게 이름을 생성합니다. 사용자가 스크롤하면 더 많은 이름이 생성됩니다. 무한하게 스크롤 할 수 있습니다.
GIF 애니메이션은 1부를 완료하면 앱이 어떻게 동작하는지를 보여줍니다.
1단계: Starter Flutter app 만들기
첫 Flutter 앱 시작하기에 있는 지침을 따라 간단한 템플릿 기반 Flutter 앱을 만듭니다. 이름을 startup_namer로 지정합니다 (myapp 대신).
코드랩에서는 주로 Dart 코드가 있는 lib/main.dart를 수정할 것입니다.
-
lib/main.dart의 내용을 바꿉니다.
lib/main.dart의 모든 코드를 삭제합니다. 화면 중앙에 “Hello World”를 표시하는 아래 코드로 대체합니다.lib/main.dart// Copyright 2018 The Flutter team. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Welcome to Flutter', home: Scaffold( appBar: AppBar( title: Text('Welcome to Flutter'), ), body: Center( child: Text('Hello World'), ), ), ); } } -
IDE에 적합한 방식으로 앱을 실행하세요. 장치에 따라, Android 또는 iOS 결과가 나와야 합니다.
안드로이드
iOS
관찰
- 이 예제는 머티리얼 앱을 만듭니다. 머티리얼은 모바일 및 웹에서 표준으로 사용되는 시각 디자인 언어입니다. Flutter는 다양한 머티리얼 위젯을 제공합니다.
-
main()메서드는 화살표(=>) 표기법을 사용합니다. 한 줄 함수 또는 메서드에 화살표 표기법을 사용하세요. - 앱은
StatelessWidget을 상속받아 앱 자체를 위젯으로 만듭니다. Flutter에서는 정렬, 여백, 레이아웃 등 거의 모든것이 위젯입니다. - 머티리얼 라이브러리의
Scaffold위젯은 홈 스크린의 위젯 트리를 구성하는 app bar, title, body 속성을 기본으로 제공합니다.
위젯 하위 트리는 상당히 복잡할 수 있습니다. - 위젯의 주된 임무는
다른 하위 위젯을 어떻게 표현할 지를 설명하는
build()메서드를 제공하는 것입니다. - 이 예제는 자식 위젯으로
Text을 포함하는Center위젯으로 구성됩니다. Center 위젯은 하위 위젯을 화면 중앙에 정렬합니다.
2단계: 외부 패키지 이용하기
이 단계에서는 가장 많이 사용되는 영어 단어 수천 개와 몇 가지 유틸리티 기능이 포함되어 있는 오픈 소스 패키지인 english_words를 이용할 것입니다.
다른 오픈 소스 패키지와 마찬가지로,
[the Package site][]에서
english_words 패키지를 찾을 수 있습니다.
-
Flutter 앱에서 의존성 및 asset 관리는 pubspec 파일이 담당합니다.
pubspec.yaml의 의존성 목록에english_words(3.1.0 이상)를 추가하세요:{step1_base → step2_use_package}/pubspec.yaml@@ -5,4 +5,5 @@55dependencies:66flutter:77sdk: flutter88cupertino_icons: ^0.1.29+ english_words: ^3.1.0 -
안드로이드 스튜디오의 편집기 화면에서 pubspec 파일을 보는 동안 나타나는 Packages get를 클릭하세요. 이렇게 하면 해당 패키지를 프로젝트로 가져옵니다. 아래와 같은 메시지를 콘솔에서 확인할 수 있습니다:
$ flutter pub get Running "flutter pub get" in startup_namer... Process finished with exit code 0또한
Packages get을 수행하면pubspec.lock프로젝트로 가져온 모든 패키지 목록과 버전 번호를 포함하고 있는pubspec.lock파일도 자동으로 생성됩니다. -
lib/main.dart에서 새 패키지를 가져오세요:lib/main.dartimport 'package:flutter/material.dart'; import 'package:english_words/english_words.dart';입력 할 때, 안드로이드 스튜디오가 import 할만한 라이브러리를 추천해줍니다. 그런 다음 import 문자열이 회색으로 나타내어 해당 라이브러리가 (지금까지는) 사용되지 않았음을 알려줍니다.
-
“Hello World” 문자열 대신 English words를 사용하여 텍스트를 생성하세요:
{step1_base → step2_use_package}/lib/main.dart@@ -9,6 +10,7 @@910class MyApp extends StatelessWidget {1011@override1112Widget build(BuildContext context) {13+ final wordPair = WordPair.random();1214return MaterialApp(1315title: 'Welcome to Flutter',1416home: Scaffold(@@ -16,7 +18,7 @@1618title: Text('Welcome to Flutter'),1719),1820body: Center(19- child: Text('Hello World'),21+ child: Text(wordPair.asPascalCase),2022),2123),2224); -
앱이 실행중이면, hot reload를 사용하여 실행중인 앱을 업데이트하세요. 실행중인 앱에서 hot reload를 클릭할 때마다 혹은 프로젝트를 저장할 때마다, 랜덤하게 선택된 다른 단어 쌍을 볼 수 있을 것입니다. 왜냐하면 MaterialApp이 렌더링 될 때마다 혹은 또는 Flutter Inspector에서 플랫폼을 전환할 때마다 실행되는 build 메서드 안에서 단어 쌍을 생성하고 있기 때문입니다.
안드로이드
iOS
문제가 있나요?
앱이 올바르게 동작하지 않는다면, 오타를 확인해보세요. Flutter 디버깅 툴을 사용해보고 싶다면, DevTools 제품군과 프로파일링 툴을 확인해보세요. 필요하다면, 아래 코드를 사용하여 다시 올바르게 동작하게 하세요.
3단계: Stateful 위젯 추가하기
Stateless 위젯은 변경불가능immutable합니다. 속성을 변경할 수 없습니다—모든 값이 final입니다.
Stateful 위젯은 위젯의 수명동안 변경될 수 있는 상태를 유지합니다. Stateful 위젯은 최소 두 개 이상 클래스가 필요합니다: 1) StatefulWidget 클래스가 2) State 클래스 의 인스턴스를 생성합니다. StatefulWidget 클래스 그자체는 변경불가능합니다. 하지만 State 클래스가 위젯의 수명동안 상태를 유지합니다.
이 단계에서는, Stateful 위젯 RandomWords를 추가하고,
그 위젯에서 State 클래스인 RandomWordsState를 생성할 것입니다.
그런 다음 RandomWords를 기존 Stateless 위젯 MyApp의 자식으로 사용할 것입니다.
-
최소한의 상태를 가지는 클래스를 생성하세요.
main.dart의 하단에 아래 코드를 추가하세요:lib/main.dart (RandomWordsState)class RandomWordsState extends State<RandomWords> { // TODO Add build() method }State<RandomWords>선언을 눈여겨보세요.RandomWords로 지정된 제네릭으로 State 클래스를 사용하고 있습니다. 대부분의 앱 로직과 상태는 여기서 유지됩니다—RandomWords위젯을 위해 상태를 보관합니다. 이 클래스에 생성된 단어 쌍이 저장됩니다. 사용자가 스크롤함에 따라 단어 쌍이 무한히 증가하고, 사용자가 하트 아이콘 스위치를 눌러 가장 좋아하는 단어 쌍을 지정할 수 있습니다(part 2에서).RandomWordsState는RandomWords클래스에 의존적입니다. 아래에서 추가할 것입니다. -
Stateful 위젯
RandomWords를main.dart에 추가하세요.RandomWords위젯은 상태 클래스를 만드는 것 이외에 별다른 일을 하지 않습니다:lib/main.dart (RandomWords)class RandomWords extends StatefulWidget { @override RandomWordsState createState() => RandomWordsState(); }상태 클래스를 추가한 후, IDE가 클래스에 build 메서드가 없다고 경고합니다. 다음으로, 기본 메서드 build를 추가하고 단어 생성 코드를
MyApp에서RandomWordsState로 옮겨 단어 쌍을 생성하도록 하세요. -
build()메서드를RandomWordsState에 추가하세요:lib/main.dart (RandomWordsState)class RandomWordsState extends State<RandomWords> { @override Widget build(BuildContext context) { final wordPair = WordPair.random(); return Text(wordPair.asPascalCase); } } -
아래 diff에 표시된 변경사항처럼
MyApp에서 단어 생성 코드를 삭제하세요:{step2_use_package → step3_stateful_widget}/lib/main.dart@@ -10,7 +10,6 @@1010class MyApp extends StatelessWidget {1111@override1212Widget build(BuildContext context) {13- final wordPair = WordPair.random();1413return MaterialApp(1514title: 'Welcome to Flutter',1615home: Scaffold(@@ -18,8 +17,8 @@1817title: Text('Welcome to Flutter'),1918),2019body: Center(21- child:Text(wordPair.asPascalCase),20+ child: RandomWords(),2221),2322),2423);2524} -
앱을 재시작하세요. 앱은 이전에 동작하던 방식과 마찬가지로 hot reload 하거나 저장할 때마다 단어 쌍을 계속 보여줘야 합니다.
문제가 있나요?
앱이 올바르게 동작하지 않는다면, 오타를 확인해보세요. Flutter 디버깅 툴을 사용해보고 싶다면, DevTools 제품군과 프로파일링 툴을 확인해보세요. 필요하다면, 아래 코드를 사용하여 다시 올바르게 동작하게 하세요.
4단계: 무한 스크롤 ListView 생성하기
이 단계에서는, RandomWordsState를 확장하여 단어 쌍 목록을 생성하고 표시합니다.
ListView 위젯 안에 표시되는 목록이 사용자가 스크롤할 때마다 무한하게 늘어납니다.
ListView의 builder 팩토리 생성자를 사용하면 필요에 따라 lazy한 방식으로 목록을 만듭니다.
-
제안된 단어 쌍을 저장하기 위해
RandomWordsState클래스에_suggestions목록을 추가하세요. 또한, 글자 크기를 키우기 위해_biggerFont변수를 추가하세요.lib/main.dartclass RandomWordsState extends State<RandomWords> { final _suggestions = <WordPair>[]; final _biggerFont = const TextStyle(fontSize: 18.0); // ··· }다음으로,
RandomWordsState클래스에_buildSuggestions()함수를 추가하세요. 이 메서드는 제안된 단어 쌍을 표시하는ListView를 만듭니다.ListView클래스는 builder 속성인itemBuilder를 제공합니다. 이 팩토리 빌더는 익명 함수 형태의 콜백 함수를 받습니다. 두 인자가 함수에 전달됩니다;BuildContext와 행 반복자i입니다. 반복자는 0부터 시작되고 함수가 호출될 때마다 증가합니다. ListTile에 제안된 모든 단어 쌍에 대해 2번씩, 그리고 Divider에 1번씩 증가합니다. 이 방식을 사용하여 사용자가 스크롤을 할 때마다 목록이 무한하게 증가할 수 있게 할 수 있습니다. -
RandomWordsState클래스에_buildSuggestions()함수를 추가하세요:lib/main.dart (_buildSuggestions)Widget _buildSuggestions() { return ListView.builder( padding: const EdgeInsets.all(16.0), itemBuilder: /*1*/ (context, i) { if (i.isOdd) return Divider(); /*2*/ final index = i ~/ 2; /*3*/ if (index >= _suggestions.length) { _suggestions.addAll(generateWordPairs().take(10)); /*4*/ } return _buildRow(_suggestions[index]); }); }-
itemBuilder콜백은 단어 쌍이 제안될 때마다 호출되고 각각을ListTile행에 배치합니다. 짝수 행인 경우ListTile행에 단어 쌍을 추가합니다. 홀수 행인 경우 시각적으로 각 항목을 구분하는Divider위젯을 추가합니다. 작은 기기에서는 구분선을 보기 어려울 수 있습니다. -
ListView의 각 행 앞에 1 픽셀 높이의 구분선 위젯을 추가하십시오. -
i ~/ 2표현식은i를 2로 나눈 뒤 정수 결과를 반환합니다. 예를 들어: 1, 2, 3, 4, 5는 0, 1, 1, 2, 2가 됩니다. 이렇게 하면 구분선 위젯을 제외한ListView에 있는 단어 쌍 수가 계산됩니다. - 가능한 단어 쌍을 모두 사용하고 나면, 10개를 더 생성하고 제안 목록에 추가합니다.
_buildSuggestions()함수는 단어 쌍 마다 한 번 씩_buildRow()를 호출합니다. 이 함수는ListTile에서 각각 새로운 쌍을 표시하여 다음 단계에서 행을 더 매력적으로 만들 수 있게 합니다. -
-
RandomWordsState에_buildRow()를 추가하세요:lib/main.dart (_buildRow)Widget _buildRow(WordPair pair) { return ListTile( title: Text( pair.asPascalCase, style: _biggerFont, ), ); } -
RandomWordsState클래스에서build()메서드를 변경하여 단어 생성 라이브러리를 직접 호출하지 말고_buildSuggestions()을 사용하도록 하세요, (Scaffold는 기본적인 머티리얼 디자인 시각 레이아웃을 구현합니다.) 메서드의 본문을 아래 강조 표시된 코드로 교체하세요:lib/main.dart (build)@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Startup Name Generator'), ), body: _buildSuggestions(), ); } -
MyApp클래스에서build()메서드를 수정하세요. title을 변경하고 home을RandomWords으로 변경하세요:{step3_stateful_widget → step4_infinite_list}/lib/main.dart@@ -10,15 +10,8 @@1010class MyApp extends StatelessWidget {1111@override1212Widget build(BuildContext context) {1313return MaterialApp(14- title: 'WelcometoFlutter',15- home:Scaffold(14+ title: 'Startup Name Generator',15+ home: RandomWords(),16- appBar: AppBar(17- title: Text('Welcome to Flutter'),18- ),19- body: Center(20- child: RandomWords(),21- ),22- ),2316);2417} -
Restart the app. You should see a list of word pairings no matter how far you scroll.
안드로이드
iOS
문제가 있나요?
앱이 올바르게 동작하지 않는다면, 오타를 확인해보세요. Flutter 디버깅 툴을 사용해보고 싶다면, DevTools 제품군과 프로파일링 툴을 확인해보세요. 필요하다면, 아래 코드를 사용하여 다시 올바르게 동작하게 하세요.
Profile or release runs
So far you’ve been running your app in debug mode. Debug mode trades performance for useful developer features such as hot reload and step debugging. It’s not unexpected to see slow performance and janky animations in debug mode. Once you are ready to analyze performance or release your app, you’ll want to use Flutter’s “profile” or “release” build modes. For more details, see Flutter’s build modes.
다음 단계
축하합니다!
iOS와 Android 모두에서 작동하는 인터랙티브한 Flutter 앱을 작성해보았습니다. 이 코드랩에서:
- Flutter 앱을 처음부터 만들었습니다.
- Dart 코드를 작성했습니다.
- 외부 서드파티 라이브러리를 활용했습니다.
- 빠른 개발 사이클을 위해 hot reload를 사용했습니다.
- Stateful 위젯을 적용했습니다.
- Lazy한 방식 무한 스크롤 목록을 만들었습니다.
이 앱을 확장하고 싶다면, 구글 개발자 코드랩 사이트에서, 2부를 진행하세요. 아래 기능을 추가하게 될 것입니다:
- 클릭 가능한 하트 아이콘을 추가하여 가장 좋아하는 단어 쌍을 저장하고 앱을 인터랙티브하게 만들어봅니다.
- 가장 좋아하는 단어를 보관하는 새로운 화면과 경로를 추가하고 그 화면으로 이동하는 내비게이션 기능을 구현해봅니다.
- 테마 색을 수정하여 흰색 앱을 만들어봅니다.