https://flutter-ko.dev/docs/get-started/install
해당 사이트에서
다음 과정을 진행하기로 했습니다.
Xcode simulator 실행 결과
Hot reload가 무엇인지 설명하기 위해서 있는 introduction
변경하고 command(⌘) + s로 저장하였다. 대략 2초 안되는 시간이 흐른 후 어플리케이션에도 변경된 것을 볼 수 있었다.
1단계: app 만들기
lib/main.dart의 내용을 바꿉니다.
lib/main.dart의 모든 코드를 삭제합니다. 화면 중앙에 “Hello World”를 표시하는 아래 코드로 대체합니다.
main() 메서드는 화살표(=>) 표기법을 사용합니다. 한 줄 함수 또는 메서드에 화살표 표기법을 사용하세요.
앱은 StatelessWidget을 상속받아 앱 자체를 위젯으로 만듭니다. Flutter에서는 정렬, 여백, 레이아웃 등 거의 모든것이 위젯입니다.
머티리얼 라이브러리의 Scaffold 위젯은 홈 스크린의 위젯 트리를 구성하는 app bar, title, body 속성을 기본으로 제공합니다.
위젯 하위 트리는 상당히 복잡할 수 있습니다.
위젯의 주된 임무는 다른 하위 위젯을 어떻게 표현할 지를 설명하는 build() 메서드를 제공하는 것입니다.
이 예제는 자식 위젯으로 Text을 포함하는 Center 위젯으로 구성됩니다. Center 위젯은 하위 위젯을 화면 중앙에 정렬합니다.
2단계: 외부 패키지 이용하기
이 단계에서는 가장 많이 사용되는 영어 단어 수천 개와 몇 가지 유틸리티 기능이 포함되어 있는 오픈 소스 패키지인 english_words를 이용할 것입니다.
다른 오픈 소스 패키지와 마찬가지로, [the Package site][]에서 english_words 패키지를 찾을 수 있습니다.
1. Flutter 앱에서 의존성 및 asset 관리는 pubspec 파일이 담당합니다. pubspec.yaml의 의존성 목록에 english_words (3.1.0 이상)를 추가하세요:
다음과 같이 project가 존재하는 폴더에 있는 pubspec.yaml파일을 다음과 같이 수정해줍니다.
2. 안드로이드 스튜디오의 편집기 화면에서 pubspec 파일을 보는 동안 나타나는 Packages get를 클릭하세요. 이렇게 하면 해당 패키지를 프로젝트로 가져옵니다. 아래와 같은 메시지를 콘솔에서 확인할 수 있습니다:
$ flutter pub get
Running "flutter pub get" in t1... 2.2s
또한 Packages get을 수행하면 pubspec.lock 프로젝트로 가져온 모든 패키지 목록과 버전 번호를 포함하고 있는 pubspec.lock 파일도 자동으로 생성됩니다.
3. lib/main.dart에서 새 패키지를 가져오세요:
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';
입력 할 때, 안드로이드 스튜디오가 import 할만한 라이브러리를 추천해줍니다. 그런 다음 import 문자열이 회색으로 나타내어 해당 라이브러리가 (지금까지는) 사용되지 않았음을 알려줍니다.
4. “Hello World” 문자열 대신 English words를 사용하여 텍스트를 생성하세요:
* 참고: “Pascal case” (“upper camel case”라고도 알려져있음)는 문자열에서 맨 처음 단어를 포함한 모든 단어의 첫번째 글자가 대문자로 시작하는 형식입니다. 그래서, “uppercamelcase”는 “UpperCamelCase”가 됩니다.
5. 앱이 실행중이면, hot reload를 사용하여 실행중인 앱을 업데이트하세요. 실행중인 앱에서 hot reload를 클릭할 때마다 혹은 프로젝트를 저장할 때마다, 랜덤하게 선택된 다른 단어 쌍을 볼 수 있을 것입니다. 왜냐하면 MaterialApp이 렌더링 될 때마다 혹은 또는 Flutter Inspector에서 플랫폼을 전환할 때마다 실행되는 build 메서드 안에서 단어 쌍을 생성하고 있기 때문입니다.
3단계: Stateful 위젯 추가하기
Stateless 위젯은 변경불가능immutable합니다. 속성을 변경할 수 없습니다—모든 값이 final입니다.
Stateful 위젯은 위젯의 수명동안 변경될 수 있는 상태를 유지합니다. Stateful 위젯은 최소 두 개 이상 클래스가 필요합니다: 1) StatefulWidget 클래스가 2) State 클래스 의 인스턴스를 생성합니다. StatefulWidget 클래스 그자체는 변경불가능합니다. 하지만 State 클래스가 위젯의 수명동안 상태를 유지합니다.
이 단계에서는, Stateful 위젯 RandomWords를 추가하고, 그 위젯에서 State 클래스인 RandomWordsState를 생성할 것입니다. 그런 다음 RandomWords를 기존 Stateless 위젯 MyApp의 자식으로 사용할 것입니다.
1. 최소한의 상태를 가지는 클래스를 생성하세요. main.dart의 하단에 아래 코드를 추가하세요:
class RandomWordsState extends State<RandomWords> {
// TODO Add build() method
}
State<RandomWords> 선언을 눈여겨보세요. RandomWords로 지정된 제네릭으로 State 클래스를 사용하고 있습니다. 대부분의 앱 로직과 상태는 여기서 유지됩니다—RandomWords 위젯을 위해 상태를 보관합니다. 이 클래스에 생성된 단어 쌍이 저장됩니다. 사용자가 스크롤함에 따라 단어 쌍이 무한히 증가하고, 사용자가 하트 아이콘 스위치를 눌러 가장 좋아하는 단어 쌍을 지정할 수 있습니다(part 2에서).
RandomWordsState는 RandomWords 클래스에 의존적입니다. 아래에서 추가할 것입니다.
2. Stateful 위젯 RandomWords를 main.dart에 추가하세요. RandomWords 위젯은 상태 클래스를 만드는 것 이외에 별다른 일을 하지 않습니다:
class RandomWords extends StatefulWidget {
@override RandomWordsState createState() => RandomWordsState();
}
상태 클래스를 추가한 후, IDE가 클래스에 build 메서드가 없다고 경고합니다. 다음으로, 기본 메서드 build를 추가하고 단어 생성 코드를 MyApp에서 RandomWordsState로 옮겨 단어 쌍을 생성하도록 하세요.
3. build() 메서드를 RandomWordsState에 추가하세요:
class RandomWordsState extends State<RandomWords> {
@override Widget build(BuildContext context) {
final wordPair = WordPair.random();
return Text(wordPair.asPascalCase);
}
}
4. 아래 diff에 표시된 변경사항처럼 MyApp에서 단어 생성 코드를 삭제하세요:
5. 앱을 재시작하세요. 앱은 이전에 동작하던 방식과 마찬가지로 hot reload 하거나 저장할 때마다 단어 쌍을 계속 보여줘야 합니다.
해당 실습에서 봤듯이 stateless라는 위젯은 변경이 불가능하기 때문에 stateful로 새롭게 선언을 해주었다고 한다. 솔직히 실습 과정에서 조금 복잡해진 것 말고는 별다른 차이를 못느끼겠다. 실행 결과도 같고(물론 침해하지 않게 구현을 했겠지만.. ) 크게 체감이 되질 않는다. 이 부분은 조금 더 배우면서 익혀봐야겠다.
4단계: 무한 스크롤 ListView 생성하기
이 단계에서는, RandomWordsState를 확장하여 단어 쌍 목록을 생성하고 표시합니다. ListView 위젯 안에 표시되는 목록이 사용자가 스크롤할 때마다 무한하게 늘어납니다. ListView의 builder 팩토리 생성자를 사용하면 필요에 따라 lazy한 방식으로 목록을 만듭니다.
1. 제안된 단어 쌍을 저장하기 위해 RandomWordsState 클래스에 _suggestions 목록을 추가하세요. 또한, 글자 크기를 키우기 위해 _biggerFont 변수를 추가하세요.
class 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번씩 증가합니다. 이 방식을 사용하여 사용자가 스크롤을 할 때마다 목록이 무한하게 증가할 수 있게 할 수 있습니다.
2. RandomWordsState 클래스에 _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]);
}
);
}
1) itemBuilder 콜백은 단어 쌍이 제안될 때마다 호출되고 각각을 ListTile 행에 배치합니다. 짝수 행인 경우 ListTile 행에 단어 쌍을 추가합니다. 홀수 행인 경우 시각적으로 각 항목을 구분하는 Divider 위젯을 추가합니다. 작은 기기에서는 구분선을 보기 어려울 수 있습니다.
2) ListView의 각 행 앞에 1 픽셀 높이의 구분선 위젯을 추가하십시오.
3) i ~/ 2 표현식은 i를 2로 나눈 뒤 정수 결과를 반환합니다. 예를 들어: 1, 2, 3, 4, 5는 0, 1, 1, 2, 2가 됩니다. 이렇게 하면 구분선 위젯을 제외한 ListView에 있는 단어 쌍 수가 계산됩니다.
4) 가능한 단어 쌍을 모두 사용하고 나면, 10개를 더 생성하고 제안 목록에 추가합니다.
_buildSuggestions() 함수는 단어 쌍 마다 한 번 씩 _buildRow()를 호출합니다. 이 함수는 ListTile에서 각각 새로운 쌍을 표시하여 다음 단계에서 행을 더 매력적으로 만들 수 있게 합니다.
3. RandomWordsState에 _buildRow()를 추가하세요:
Widget _buildRow(WordPair pair) {
return ListTile(
title: Text(
pair.asPascalCase, style: _biggerFont,
),
);
}
4. RandomWordsState 클래스에서 build() 메서드를 변경하여 단어 생성 라이브러리를 직접 호출하지 말고 _buildSuggestions()을 사용하도록 하세요, (Scaffold는 기본적인 머티리얼 디자인 시각 레이아웃을 구현합니다.) 메서드의 본문을 아래 강조 표시된 코드로 교체하세요:
@override Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Startup Name Generator'),
),
body: _buildSuggestions(),
);
}
5. MyApp 클래스에서 build() 메서드를 수정하세요. title을 변경하고 home을 RandomWords으로 변경하세요:
다음과 같이 무한 스크롤이 완성되었습니다.
해당 프로젝트는 깃허브에 연동됩니다.
https://github.com/gurcks8989/Flutter/tree/master/t1
https://github.com/gurcks8989/Flutter/blob/b6f231f7eb4f84fd7dbf3f99e394ef92aedfd47c/t1/lib/main.dart