상세 컨텐츠

본문 제목

02) Flutter 개발 시작하기

Programming/Flutter

by 양명 2019. 5. 26. 18:59

본문

이번 장에서는 Flutter 개발 환경 셋팅, 기본 Flutter 앱 생성하기를 해보겠습니다. Flutter 앱 생성 후에는 AVD로 화면을 띄워보고, 외부 패키지 사용, 그리고 Stateful 위젯 추가 방법까지 알아보겠습니다.

 

본격적으로 Flutter 개발을 시작하기 위해 Flutter 개발 블로그를 참고하여 진행합니다

https://flutter.dev/docs/get-started/install

 

Install

Select the operating system on which you are installing Flutter:{{site.alert.note}} **Are you on Chrome OS?** If so, see the official [Chrome OS Flutter installation docs!](/docs/get-started/install/chromeos){{site.alert.end}}

flutter.dev

 

위 링크에서 Get Started 부분을 따라 개발 환경 셋팅을 따라 가 주시면 됩니다.

순서대로만 하면 딱히 어려운 점은 없으니 Install 및 Editor 셋업은 개발 블로그를 참고하여 진행해주세요.

 

=======================================

1) 기본 소스코드 구조 설명

Get Started - 4. Write your first app 부분을 보면 Flutter 모바일 앱 개발에 사용되는 기본 소스코드 form 부터 시작해서 코드 구조를 설명해 줍니다.

개발 블로그에 제공되는 샘플 코드를 분석하자면, 아래 키워드들을 확인할 수 있습니다.

Material app, main() 메소드, StatelessWidget, Scaffold, build() 메소드 등이 있네요.

먼저 Material app이란 모바일 및 웹에서 표준인 Visual design language라고 합니다. 한 문장으로 이해하기 어렵지만 일단 개념만 익혀두고 전체 코드를 보도록 할께요.

Main() 메소드는 =>노테이션 사용하는 걸 볼 수 있는데 Dart에서 이렇게 한 줄로 함수나 메소드를 표현하나 봅니다. 

StatelessWidget은 MyApp 클래스에서 확장하여 사용하고 있는데, 앱 자체를 위젯으로 만드는 클래스입니다. Flutter에서는 정렬이나 레이아웃 같은 것들을 포함하는 거의 모든것이 하나의 위젯에 들어가 있습니다.

Scaffold 위젯은 Material library에 저장된, 디폴트 App bar, 타이틀, body property를 홈 스크린에 위젯 트리 형태로 제공하는데 이 위젯 하위 트리는 꽤 복잡하게 구성되어 있습니다.

위젯의 주 기능은 다른 하위 레벨의 위젯 관점에서 어떻게 위젯을 표시할 건지를 설명하는 build() 메소드를 제공하는 것인데, build()메소드 내부를 보시면 크게 title과 home으로 나뉘며, home 내부에서는 appBar와 body로 나뉩니다.

이 샘플 코드에서는 body에 텍스트 자식을 갖는 Center 위젯이 있는데 Center 위젯은 자신의 하위 트리 위젯 화면 가운데로 맞추는 역할을 합니다.

아래 사진은 AVD Manager로 실행한 화면입니다.

 

================================

2) 외부 패키지 사용하기

다음은 외부 패키지 사용 방법에 대해 알아보겠습니다!

위 사진처럼 프로젝트 뷰에서 pubspec.yaml을 열어보면, dependency를 설정할 수 있는 파일임을 알 수 있습니다.
중간에 빨간 박스 친 english_words 부분을 적고 Packages get을 클릭하면 해당 패키지가 프로젝트로 다운로드됩니다.

다시 main.dart로 돌아와서 코드를 아래처럼 수정해주세요.

수정 후 저장 혹은 'Flutter Hot Reload'를 하면 앱 재시작 필요 없이 기기에 바로 수정사항이 반영됩니다.

Hot Reload 버튼을 계속해서 클릭하면 외부 패키지 english_word로 인해 단어가 계속 바뀌는 것을 알 수 있습니다.
예제 소스에 이런 외부 패키지를 사용했는데 이런 무작위 단어들을 어디에 써먹을 수 있을지... 모르겠네요 -_-;;

==========================================

3) Stateful 위젯 추가하기

Stateful 위젯은 해당 위젯의 생명주기 동안 변경될 수 있는 상태를 유지합니다. Stateful 위젯을 구현하려면 최소 2개 클래스가 필요한데, 첫 번째는 객체를 생성하는 StatefulWidget 클래스. 두 번째는 State 클래스입니다.

Stateful 위젯을 구현하기 위해 위 사진의 내용을 main.dart에 작성해주세요. (MyApp 클래스 밖에서 작성)
앞 서 말씀드렸듯이, 첫 번째 클래스는 State 클래스를 확장한 클래스로, StatefulWidget 클래스 자체는 불변이지만 State클래스는 위젯 생명주기 동안 지속됩니다.

RandomWords 클래스에서는 StatefulWidget을 확장했기 때문에 기본적으로는 State<StatefulWidget> createState(){return null}을 overriding해야 합니다. State 클래스를 확장한 RandomWordsState 클래스 타입으로 createState() => RandomWordsState() 객체를 생성했습니다.

 

그리고 main.dart에서 MyApp 클래스를 위와 같이 수정해줍니다.

그 후 저장하거나 Hot reload 클릭하게 되면 2)번 예제 소스의 결과와 같이 단어가 바뀌는 것을 확인할 수 있습니다.

==========================================

4) 무한 스크롤 ListView 생성하기

이번에는 위에 생성했던 영단어 외부 패키지를 활용하여 여러가지 영어 단어 값들을 스크롤 할 수 있는 ListView를 생성 해보겠습니다.

3)에서 작성했던 소스코드를 이어서 사용하면 되고, 위 사진처럼 RandomWordsState 클래스에 영단어 배열을 저장할 _suggestions 변수와 폰트 사이즈를 설정하기 위한 _biggerFont 변수를 선언해줍니다.
-------------------------------------------------------------------------
final _suggestions = <WordPair>[];
final _biggerFont= const TextStyle(fontSize: 18.0);
-------------------------------------------------------------------------

다음은 마찬가지로 RandomWordsState 클래스에 _buildSuggestions() 메소드를 생성합니다.

_buildSuggestions() 메소드는 영어 단어들을 표시해줄 ListView를 빌드하는 메소드입니다. 이 메소드에는 itemBuilder라고 하는 빌더 프로퍼티를 제공하는데, itemBuilder는 하나의 팩토리 빌더와 하나의 익명 함수로써 콜백 함수입니다.(?)
이 메소드는 BuildContext와 row iterator인 i, 이 두 개의 파라미터를 갖는데 i는 0부터 메소드가 호출 될 때마다 증가합니다. 
ListTile에 한 번, Divider에 한 번 모든 단어 쌍(word pairing?)에 대해 두 번씩 증가합니다.(?)
이 모델은 유저 스크롤이 무한정으로 리스트 될 수 있게 해줍니다.

-------------------------------------------------------------------------
Widget _buildSuggestions() {
   return ListView.builder(
      padding: const EdgeInsets.all(16.0),
      itemBuilder: (context, i) {
         if (i.isOdd) return Divider();
         final index = i ~/2;
         if (index >= _suggestions.length) {
            _suggestions.addAll(generateWordPairs().take(10));
         }
         return _buildRow(_suggestions[index]);
      }
   ));
-------------------------------------------------------------------------

위 사진에서 /*숫자*/ 주석에 대한 부분의 설명을 덧붙이자면, 

/*1*/의 itemBuilder 콜백은 제안된 단어 쌍에 한 번 호출되며, 각 단어를 ListTile 행에 배치합니다.
짝수 행의 경우에는 메소드에서 단어가 배치될 행을 배치하기 위한 하나의 ListTile 행을 추가합니다.
홀수 행의 경우는 시각적으로 단어들을 분리하기 위해 Divider 위젯을 추가합니다.
divider는 작은 디바이스에서는 잘 보이지 않을 수 있습니다.
/*2*/에서는 ListView의 각 행 전에 1픽셀 높이의 divider 위젯을 추가합니다. 
/*3*/에서 "i ~/ 2" 표현식은 2로 나눈 후 값에서 정수 부분에 해당하는 값을 리턴합니다. 
(예: i가 1,2,3,4,5일 때 리턴 값은 0,1,1,2,2 입니다.)
인덱스를 이와 같이 표현한 이유는 홀수 행에서 divider를 추가 하기 때문에 실제 단어의 수 만큼 계산하기 위함입니다.
/*4*/에서는 외부 패키지로부터 가져온 단어들이 한계에 도달했을 때, 10개 더 생성하고 제안 리스트에 그들을 추가합니다(?)
최종적으로 _buildSuggestions() 메소드는 _buildRow를 각 영어 단어 당 한 번 호출합니다.  

다음은 아래 사진과 같이 _builderSuggestions() 메소드 아래에 이어서 _buildRow() 메소드를 추가 작성 합니다.

-------------------------------------------------------------------------
Widget _buildRow(WordPair pair) {
   return ListTile(
      title: Text(
         pair.asPascalCase,
         style: _biggerFont,
      ),
   );
}
-------------------------------------------------------------------------

RandomWordsState 클래스에서 직접 단어 생성 라이브러리를 호출하는 것 보다 _buildSuggestions() 메소드를 사용하기 위해 build() 메소드를 위 내용과 같이 수정 합니다.
Scaffold는 MaterialApp과 유사하게 기본 Material Design Visual 레이아웃을 구현합니다.

 

마지막으로 MyApp 클래스에서 아래 사진과 같이 build()메소드를 수정해줍니다. MyApp 클래스에서 home 부분에 RandomWords()를 호출하게 됩니다.

 

 

전체 소스 코드

-------------------------------------------------------------------------
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Startup Name Generator',
home: RandomWords(),
);
}
}

class RandomWordsState extends State<RandomWords> {
final _suggestions = <WordPair>[];
final _biggerFont = const TextStyle(fontSize: 18.0);
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]);
});
}

Widget _buildRow(WordPair pair) {
return ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
);
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Startup Name Generator'),
),
body: _buildSuggestions(),
);
}
}

class RandomWords extends StatefulWidget {
@override
RandomWordsState createState() => RandomWordsState();
}
-------------------------------------------------------------------------

실행 결과

ListTile 사이사이 보이는 선이 divider 입니다!

 

다음 포스팅에서는 Flutter 개발 블로그의 Learn more 부분 중, 첫 번째 파트인 

Flutter basics

여러 위젯 소개와 두 가지 튜토리얼을 함께 따라해 보겠습니다.

 

 

 

'Programming > Flutter' 카테고리의 다른 글

Flutter 개발. 1) Flutter란?  (0) 2019.05.19

관련글 더보기