[flutter] 플러터로 첫번째 앱 만들기
출처 : https://codelabs.developers.google.com/codelabs/first-flutter-app-pt1/#0
1. 소개
- 플러터는 iOS 및 Android 둘다 개발 할 수 있는 구글의 모바일 SDK 입니다.
- 플러터는 무료며 오픈소스 입니다.
- 객체 지향 코드 및 기본 프로그래밍에 대해 알고 있다면 좀 더 손쉽게 접근 할 수 잇습니다.
- 다트 또는 모바일 프로그래밍에 대한 경험이 없어도 시작하실 수 있습니다.
1.1. part 1 에서 배우는 것들
- 플러터 앱을 iOS / Android 처럼 보이게 작성하는 방법
- 플러터 앱의 기본 구조
- 기능 확장을 위한 패키지 검색 및 사용방법
- 핫 리로드를 활용하여 개발 주기를 단축하는 방법
- 스테이트풀 위젯 구현하기
- 데이터가 느리게 로딩되는 무한 목록 만드는 방법
1.2. 만드려는 플러터 앱의 목표
- 무한 스크롤
- 스크롤 시 하위 데이터가 로딩이 된 이후 목록을 표시해 주도록 함
1.3. 개발환경 설정
개발 환경이 구성되지 않은 경우, 링크를 클릭하여 관련 정보를 확인 바랍니다.
- Flutter SDK 설치
- Editor 설치
- 디바이스 ( Android, iOS ) 준비하기
- iOS 시뮬레이터 준비하기 ( XCode 설치를 필요로 합니다 )
- Android 시뮬레이터 준비하기 ( Android Studio 설치를 필요로 합니다 )
1.4. 플러터 앱 만들기
IDE 에서 "New Flutter Project" 메뉴가 보이지 않는 경우 plugin 을 설치 하시기 바랍니다.
- vscode 에서는 플러그인 설치 후 shift + cmd + p 버튼을 누른 이후 타이핑 하면
New Flutter Project
를 확인 할 수 있습니다. - AndroidStudio 에서는 플러그인을 설치 후 메뉴가 생성됨
기본 소스코드 (Hello world)
아래 코드를 변형하면서 작업을 진행할 예정 입니다.
TIP : 코드 정리하기
개발하다 보면 글의 간격이(줄맞춤) 어긋나서 코드의 가독성이 떨어지는데, 이때 Android Studio/IntelliJ IDEA 에서는 우클릭 후
Reformat Code with dartfmt
, vscode 에서는 우클릭 후Format Document
, terminal 에서는flutter format <filename>
을 입력하면 코드가 정렬되는 것을 확인할 수 있습니다.
1.5. 기본 소스
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: const Text('Welcome to Flutter'),
),
body: const Center(
child: const Text('Hello World'),
),
),
);
}
1.6. 살펴보기
- Material은 모바일 웹 표준 디자인 언어 입니다. 플러터는 다양한 Material 위젯을 제공 합니다.
=>
화살표 함수를 활용하여 코드를 간결하게 줄일 수 있습니다.- 플러터에서 대부분의 위젯은 정렬, 패딩, 레이아웃 속성을 포함하고 있습니다.
- 머티리얼 라이브러리의
Scaffold
위젯은 기본 앱 바, 제목 및 홈 스크린의 위젯 트리를 포함하는 본문 속성을 제공합니다. 위젯 하위 트리는 상당히 복잡 할 수 있습니다. (우선적으로 필요 속성부터 배워나가면 좋아요) - 위젯의 주된 임무는 다른 하위 레벨 위젯의 관점에서, 위젯을 표시하는 방법을 설명하는
build
메소드를 제공하는 것입니다.
2. 외부 패키지 사용하기
- english_words 라는 영단어를 제공해주는 무료 오픈소스 패키지를 사용해 보겠습니다.
- Pub Site 에 접속해서 다양한 flutter 기반 패키지를 검색 할 수 있습니다.
2.1. 패키지 정보를 추가
pubspec.yaml
파일을 열어 패키지 정보를 추가 합니다.
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
english_words: ^3.1.0 # 이 라인을 추가하면 됩니다.
2.2. 의존성 다운로드
packages get
명령을 통해 추가된 의존성(dependencies) 정보를 다운로드 합니다.
flutter packages get
Running "flutter packages get" in startup_namer...
Process finished with exit code 0
2.3. 소스 import 추가
소스(
lib/main.dart
) 상단에 패키지 정보를 추가 합니다.
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart'; // 이 라인 추가
2.4. 최종 소스
실행 할 때 마다 (hot deploy) 중앙의 단어가 변경되는 것을 확인할 수 있습니다
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) {
final wordPair = WordPair.random(); // Add this line.
return MaterialApp(
title: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
body: Center(
//child: Text('Hello World'), // Replace this text...
child: Text(wordPair.asPascalCase), // With this text.
),
),
);
}
}
3. StatefulWidget(상태 변화 있는 위젯) 추가하기
StatelessWidget
은 변경할 수 없으므로 해당 속성을 변경할 수 없습니다.StatefulWidget
은 위젯의 수명 기간 동안 변경 될 수 있는 상태를 유지 합니다.- 이번엔 Stateful 클래스 인 RandomWordsState를 생성 및 활용해 보도록 하겠습니다.
- State 만들기 => StatefulWidget 만들기
3.1. 상태 클래스 최소 버전
State<RandomWords>
RandomWords 클래스에서 사용하는 상태(State)를 구현한 클래스 입니다.
class RandomWordsState extends State<RandomWords> {
// TODO Add build method
}
3.2. StatefulWidget 만들기
StatefulWidget
위젯을 상속받아 클래스를 만들고, 상태변화를 담당할 클래스(RandomWordsState
)를 지정 합니다.
class RandomWords extends StatefulWidget {
@override
RandomWordsState createState() => RandomWordsState();
}
3.3. 상태 구현
RandomWords
클래스에서 상태가 변화하면build
구문을 자동적으로 수행
class RandomWordsState extends State<RandomWords> {
@override // Add from this line ...
Widget build(BuildContext context) {
final WordPair wordPair = WordPair.random();
return Text(wordPair.asPascalCase);
} // ... to this line.
}
3.4. 최종 소스
이전과 비교해 보면 main에서 랜덤 단어를 생성한 것을
StatefulWidget
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: 'Welcome to Flutter',
home: Scaffold(
appBar: AppBar(
title: Text('Welcome to Flutter'),
),
body: Center(
child: RandomWords(),
),
),
);
}
}
class RandomWordsState extends State<RandomWords>{
@override
Widget build(BuildContext context) {
final WordPair wordPair = WordPair.random();
return Text(wordPair.asPascalCase);
}
}
class RandomWords extends StatefulWidget {
@override
RandomWordsState createState() => RandomWordsState();
}
4. 무한 스크롤 만들기
ListView 의 factory build 생성자를 사용하여, 스크롤 할 때 목록을 느리게 빌드 할 수 있습니다. (필요 시 목록을 동적으로 생성하므로 효율적)
- [참조]
_
(언더스코어) 로 시작하면 dart 언어에서는 private 으로 인식하게 됩니다.
4.1. 값 추가
단어 목록 정보와, 텍스트 스타일을 추가 합니다
class RandomWordsState extends State<RandomWords> {
// 아래 두 라인 추가
final List<WordPair> _suggestions = <WordPair>[];
final TextStyle _biggerFont = const TextStyle(fontSize: 18);
...
}
4.2. 목록(ListView.builder) 만들기
Widget _buildSuggestions() {
return ListView.builder(
padding: const EdgeInsets.all(16),
// itemBuilder는 대상 아이템을 만들어주는 역할을 합니다.
// 인덱스가 홀수냐 짝수냐에 따라 대상 항목(ListTile)을 보여주거나 구분선(Divider)을 보여줍니다.
itemBuilder: (BuildContext _context, int i) {
// 인덱스가 홀수인 경우 구분선을 보여준다
if (i.isOdd) {
return Divider();
}
final int index = i ~/ 2; // 나누기를 하면 double 임 하지만 ~/ 연산자를 통해 int로 바꿔준다 == (a / b).truncate().toInt() 와 동일한 값 임.
// i : itemBuilder 내부에 들어가는 실제 항목의 index 값
// index : i를 2로 나눈 값 ( 홀수 라인에 구분선이 들어가기 때문 )
// 목록이 증가한 경우에만 값을 더 추가하는 엑션을 처리, 이미 추가한 값은 더이상 추가하지 않음
// print('$i ::: $index');
if (index >= _suggestions.length) {
// index 값이 _suggestions 길이보다 커지는 경우
_suggestions.addAll(generateWordPairs()
.take(10)); // 단어 목록에서 10개를 _suggestions 목록 정보에 추가한다
}
// item 인덱스(i)가 짝수인 경우에는 해당 _suggestions 인덱스(index)에 값을 보여주도록 한다
return _buildRow(_suggestions[index]);
});
}
4.3. Row (ListTile) 만들기
Widget _buildRow(WordPair pair) {
return ListTile(
title: Text(
pair.asPascalCase,
style: _biggerFont,
),
);
}
5. 기타 참조
맺음말
- 4개로 나눠서 하려다가 그냥 한개로 만들었네요
- 실제 하나하나 따라가면서 학습하면서 하니 시간이 좀 걸리네요 후...
- 궁금한 것은 언제든지 댓글 문의 바랍니다.
헉~~~~ 또 피곤!! ㅋㅋ 즐거운 불금 되세요^^
안피곤님이 출동 할 것입니다 / 즐거운 주말 보내세요~~ @anpigon
ㅋㅋㅋ 지난번 처럼 또 안피곤~ 댓글 다실듯...
안피곤합니드앙~
오 관심있는데 좋은 포스팅감사합니다.
한번 해봐야겠어요~
넵 :) 즐거운 코딩 라이프 즐기세여 ~
Thank you for your continued support towards JJM. For each 1000 JJM you are holding, you can get an additional 1% of upvote. 10,000JJM would give you a 11% daily voting from the 600K SP virus707 account.
Thank you for your continued support towards JJM. For each 1000 JJM you are holding, you can get an additional 1% of upvote. 10,000JJM would give you a 11% daily voting from the 600K SP virus707 account.
원사마님 플러터 진도가 넘 빨라요.😀👍