플러터 시작하기
Flutter 홈 페이지에서 튜토리얼 따라하기중..
flutter
- 1. 개요
- 2. 설치된 앱 확인
- 3. Flutter 앱 개발 다시 시작하기
-
Write Your First Flutter App, part 2
- 4. Add icons to the list
- 5. Add interactivity
- 6. Navigate to a new screen
- 7. Change the UI using themes
- 4. Build the main user interface
- 5. Add a UI for composing messages
- 6. Debug your app
- 7. Add a UI for displaying messages
- 8. Animate your app
- 9. Apply finishing touches
- 10. Next steps
- 11. Optional: Get the sample code
- TroubleShooting
1. 개요
- flutter 앱을 만들기 시작할 때 확인해야 하는 작업
2. 설치된 앱 확인
- 안드로이드 스튜디오 설치
- 플러터 SDK 설치
- 내 메인 컴은
d:/App/flutter/에 설치 ( 2021-07-07에 확인) - 설치 여부 확인 방법 ( Powershell 환경 가정)
1 2
> cd d:/App/flutter/bin > flutter doctor
- 내 메인 컴은
- 안드로이드 스튜디오에 플러터와 다트 플러그인 설치
-
[File ⇒ Setting ⇒ Plugins]에서Flutter와Dart플러그인이 설치되어있는지 확인
-
간단한 dart 코드 확인
- 간단한 dart 코드 실행 확인하는 사이트 : dartpad
flutter 업그레이드 하기
- 참조 링크: Upgrading Flutter, docs.flutter.dev
- 선택된 채널에 따라 버전이 다름 (stable, beta, master)
-
flutter channel stable: stable 채널로 선택하기- 2022-05-18 현재 버전 3.0 배포중
-
flutter upgrade: 업그레이드 실행
3. Flutter 앱 개발 다시 시작하기
- 오랫만에 다시 개발을 재개할 경우 따라할 Step by Step
-
이 곳 에 있는
Get started를 기반으로 한다
Quick Re-start
- Editor, SDK, AVD 등 필요한 패키지가 모두 설치된 초기상태에서 시작한다
-
Create the app : 신규 프로젝트 생성
-
Run the app: 앱 실행 - 환경이 준비되었는지 확인하는 의미
-
-
Step 1: Create the starter Flutter app
- 템플릿에서
main.dart만 변경한 것 - 기본 구조를 파악한다
-
Observations
- 이 예제는
Material app을 생성하는 것 - root 폴더에서
pubspec.yaml파일에uses-material-design: true로 설정하면 Material 아이콘등을 사용할 수 있다 - Javascript와 같이 method 생성시 arrow(=>) notation을 사용할 수 있다
- app이 StatelessWidget을 상속받는데 app 자체를 하나의 위젯으로 만든다
- Scaffodle widget은 제목과 바디로 이루어진 간단한 앱의 빼대를 만드는 위젯이다
- 내부 subtree는 복잡해질 수 있다
- 위젯의 주요 작업은 build() method를 호출하는 것으로
- 하위 수준 위젯의 측면에서 위젯을 어떻게 display할지 묘사하는 것이 주요 작업이다
- 이 위젯의 body는
Center위젯으로 구성되는데-
Center는Text자식 위젯을 포함한다. -
Center는 자신의 subtree를 center에 위치시킨다
-
- 이 예제는
- 템플릿에서
-
Step 2: Use an external package
- Step 1 에서 추가된 건
english_words라는 외부 패키지를 사용해보는 것- 외부 패키지 사용을 위해…
-
import로 pub.dev의englisht_words패키지 추가- pubspec.yaml 의
dependencies섹션에 추가 -
Pub get수행 : dependencies 설치 -
lib/main.dart에 import 추가1
import 'package:english_words/english_words.dart'
- pubspec.yaml 의
-
- 외부 패키지 사용을 위해…
- Step 1 에서 추가된 건
-
Step 3: Add a Stateful widget
- Stateless widgets 과 Stateful widgets 의 차이점 원문에서 읽어볼것
- StatefulWidget 구현시에 필요한 두가지
-
StatefulWidgetclass 는 그 자체는 변경불가(immutable)하고 버리고 새로 만들수 있지만,.. -
Stateclass 는 widget의 수명주기 동안 유지된다
-
- stateful widget의 boilerplate code를 자동 생성하는 keyword가 있다 (마치 emmet 처럼..)
-
stful의 typing을 시작하면 물어보는 창이 뜨는데 Return을 쳐준다
-
-
RandomWords를 widget의 이름으로 입력 한다 (그냥 번역)-
RandomWordswidget은Stateclass를 생성하는 것 외에 몇가지를 더 수행한다 -
RandomWords를 stateful widget의 이름으로 입력하면,- 같이 따라가는
Stateclass에_RandomWordsState의 이름을 IDE가 자동적으로 넣어 완성해준다 - 기본적으로,
Stateclass의 이름 앞에 underbar가 붙는다 - 이름 앞의 underscore 는 Dart 언어에서 private 속성을 적용 ( enforces privacy) 을 의미하며
-
Stateobjects의 best practice 로 추천된다
-
- 같이 따라가는
-
- 또한, IDE는 state class를
State<RandowmWords>로 부터 자동적으로 확장하는데,-
RandomWordswidget에 특화된 제네릭Stateclass 를 사용한다는 것을 가리킨다 - 대부분의 앱의 logic은 이곳에 위치한다 - 그것은
RandomWordswidget의 state를 관리한다 - 이 class는 생성된 단어쌍들의 목록을 저장한다
- 이 단어쌍의 목록은 사용자가 스크롤 할수록 무한히 커진다
- 그리고 이 codelab의 파트2에서는
- 사용자가 하트 아이콘을 토글해서 좋아하는 단어쌍을 추가하거나 제거합니다
-
-
Step 4: Create an infinite scrolling ListView
-
_RandomWordsState를 확장하여 단어쌍을 생성하고 display할 것이다 - 사용자가 목록을 스크롤하면 (
ListViewwidget 으로 보인다 )
-
Write Your First Flutter App, part 2
4. Add icons to the list
- part 1을 했으면 여기서 부터 다시 시작
-
Settype 을 처음 써봄. 사용자가 하트 표시한 WordPair 를 저장할 예정- 이 경우에는
List보다Settype 이 선호된다고 함- 이유는
Set이 중복을 허용하지 않기 때문임 - 별다른 index를 관리하지 않으므로
Set에 저장하는 것만으로 중복금지가 구현되어 효율적인듯..
- 이유는
- ListTile 결과에 하트 아이콘 붙이기 - 아직 탭은 안됨
- 이 경우에는
5. Add interactivity
- 여기서는 하트 아이콘을 tappable 하도록 할 것임
-
ListTitle에서 onTap 파라미터 활성화 ▶ setState()를 호출 - Tip.
- Flutter의 reactive style framework 에서
-
setState()를 호출하는 것은,State객체에 대해build()method 를 trigger 하는 것으로… - 결과적으로, UI를 업데이트 하도록 함
6. Navigate to a new screen
- 여기서는 (Flutter에서 route 라고 불리는) 새로운 페이지를 추가하여 하트 아이콘 설정한 것만 보여준다
- 더불어서, home route와 new route 간을 어떻게 오가는지 배운다
- Flutter 에서는,
Navigator가 app의 route들을 보관하는 stack을 관리한다-
Navigator의 stack 위로 route을 pushing 하면 해당 route로 display를 업데이트 한다 -
Navigatoer의 stack에서 route를 poping 하면 이전 route로 display가 전환 된다
-
- 다음으로,
_RamdomWordsState의buildmethod의AppBar에 list icon을 추가한다- 사용자가 이 list icon을 click하면,
- favorite 들이 저장된 새로운 route를
Naviagro에 pushing 하고 , icon을 보여준다
- Tip :
- 어떤 widget 속성은 하나의 widget (child) 으로만 설정하지만
-
action갈은 속성은 widget 의 배열 (children)으로 설정된다
- 다음으로, route를 하나만들어서
Navigator의 stack으로 push한다- 이 action은 스크린이 새로운 route를 display하도록 한다
- 새로운 페이지의 내용은
MaterialPageRoute의builderproperty 안에서 anonymous function으로 구성된다
-
Navigator.ofcall에서contextargument란 무엇일까?-
아래
BuildContext에 대해 설명하는 video를 확인하라- widget 의 constructor를 호출하면
- Flutter Frameworkd이 “createElement()” method를 호출
- 이 method는 이 widget의 element를 frameworkd에 return
- framework이 “build(context)” method를 호출하면, 이전에 생성돈 element가 context parameter의 argument로 전달됨
- 이렇게 build() method 안에서 context(element object’s) properties와 method를 사용할 수 있다
-
- 다음으로,
MaterialPageRoute와 builder를 추가할 것이다.- 일단 지금은,
ListTiel행을 생성하는 code를 추가한다 -
ListTile의divideTiles()method 는 각ListTile간에 수평 간격을 추가한다 -
devided변수는 convenience functiontoList()를 이용해 list로 변환된 마지막 행을 hold한다. - (역자주) 여기에 추가된 코드를 나름대로 해석
- _pushSaved()는 하트 아이콘 누를 때 동작하는 callback으로 설정됨
- 하트 아이콘 누를 때 해야할 동작 = _pushSaved()
- _saved set iterable 각각에 대해 Tile 생성
- 하트 아이콘 누를 때 해야할 동작 = _pushSaved()
- Navigator 는 Route (별도 페이지)를 저장할 수 있는 stack
- Navigator.push는 stack에 Route(페이지)를 push 한다는 의미
- 그럼 push 내부에서는 Route 를 빌드하는 코드가 들어가야함
- 그게 MaterialPageRoute
() - 그 내부에서 Scaffold() 형식으로 반환 하는 builder를 파라메터로 넘겨줌
- Scaffold 에서 파라미터로 사용하는 body를 ListView로 만들 때 list로 입력하므로
- 최종결과인 divided는 toList()로 형식을 변환함
- 그게 MaterialPageRoute
- _pushSaved()는 하트 아이콘 누를 때 동작하는 callback으로 설정됨
- 코드상에 Navigator.pop 을 명시하지 않아도 back 버튼이 생김
- 일단 지금은,
7. Change the UI using themes
- 앱의 look and feel을 바꾸기 위해 theme을 customize 할 수 있다
-
ThemeDataclass를 건드려서 , app 의 default theme중 primary color만 ‘white’로 바꿔본다
-
4. Build the main user interface
- 새로운 프로젝트 시작
- 👁🗨 시작코드 Observations
- 모든 Dart 프로그램은
main()으로 시작한다- command-line app, AngularDart app, Flutter app 이건 상관없이…
-
main()과runApp()함수 definitions은 자동 생성된 app에서와 동일함 -
runApp()함수는Widget을 argument로 취한다. - 이 chat app은 UI에서 Material Design elements를 사용한다
- 그래서
MaterialApp객체를 생성하고runApp()함수의 argument로 넘겨준다 -
MaterialAppwidget은 당신 app의 widget tree의 root가 된다
- 그래서
-
homeargument는 당신의 app에서 사용자가 보는 default screen을 지정한다- 이 경우에, 그것은
Scaffoldwidget으로 구성되는데, (Scaffold는) child widget으로 간단한AppBar를 포함한다 - 이 것이 Materail app의 전형적인 모습이다
- 이 경우에, 그것은
- 모든 Dart 프로그램은
-
Runicon으로 실행시키면, 처음에는 오래걸리지만 다음번 부터는 빨라질 것이다- Hot restart와 Full restart가 있다. 상세내용은 원문 확인
Build the chat screen
- interactive components의 기초를 다지기 위해, 앱을 두 개의 서로 다른 subclass로 분리한다
- root-level
FriendlyChatappwidget : 절대 안바뀐다 - a child
ChatScreenwidget : 메시지가 전달되거나 내부 상태가 변하면 rebuild 된다
- root-level
- 지금은, 위 두 classes를
StatelessWidget에서 확장해도 된다.- 나중에,
ChatScreen을 stateful widget으로 변경하게 된다. - 이런식으로, 필요한 때에 widget의 state를 변경할 수 있다
- 나중에,
- ▶ 표시가 있는 직접 해보기에서 Android Studio Editor의 자동 제안 사용하는 방법 배움
- Tip : 에서 코드 창 오른쪽 클릭하면 나오는 Context menu에서
Reformat with dartfmt사용법 배움 - 👁🗨 Observations
- 이번 step 는 Flutter framework의 몇가지 key concepts에 대해 소개함
-
build()method에서 widget으로 표시되는 user interface의 일부를 describe 했다.- frameworkd은
FriendlyChatApp왜ChatScreen의build()method를 호출하면서, - 이 widget들을 widget hierarchy에 넣었고 그들의 dependencies가 변경되었다
- frameworkd은
-
@override는 Dart annotation 인데,- 이것으로 tagging된 method가 superclass의 method를 override 한다는 의미이다
-
Scaffold나AppBar같은 일부 widget들은,Material Designapps에 specific 한 것들이다-
Text같은 다른 widgets은 일반적인 것들이며, 어느 app에서나 사용할 수 있다 - Flutter frameworkd의 다른 library들로 부터온 widget들 도 한 개의 app에서 호환하여 쓸 수 있다
-
- hot reload가
main()을 다시 실행하지 않기 때문에 ,main()method를 간소화하여 hot reload를 enable 시킨다
- hot reload ⚡버튼을 click하여 즉시 변화하는 것을 보자
- UI를 class들로 분리한 후 root widget을 변경해도 UI에서는 visible change가 안보일 것이다
- Tip:
- hot reload이후 red screen을 보게 되면, hot restart를 시도하라
- 그래도 문제가 해결되지 않으면,
- app을 멈추고, full restarte를 수행하라
- hot reload는 existing widgest들의 state를 변경한당
- 예를들어 hot reload전에 widget을 지운다면 , red screen이 발생할 수 있다
- frameworkd이 그런 older widgets를 업데이트 하려고 시도할때 app이 fail 날 수 있다
5. Add a UI for composing messages
- device에서 text field에 들어가면 soft keyboard가 뜬다
- 비어있지 않은 창에 chat messages type하고 Return key를 치거나
- graphical Send button 으로
- chat screen을 일단 위쪽에 만들거지만, 나중에 아래쪽으로 옮길것이다
Add an interactive text input field
- Flutter framework 는
TextField라고 불리는 *Material Design widget` 을 제공한다- 이것은 mutable state를 갖는
StatefulWidget으로 input field의 동작을 customizing하는 속성을 가진다 -
State는 widget이 빌드될 때 synchronous하게 읽을 수 있고 widget의 수명중에 변경될 수 있는 정보이다 - FriendlyChat app에 첫번째 stateful widget을 추가하기 위해 몇가지 modifications이 필요하다
-
ChatScreenclass 를 statefule하게 변경하기- 선택후 Alt+Enter로 메뉴 불러와서
Convert to StatefulWidget으로 선택하여 변경하기 - Tip : identifier에 underscore(_)를 붙여서 library 상에서 identifier를 private 하게 만든다.
- Dart library는 일련의 calsses, constants, functions, typedefs, properties, exceptions를 one package에 담았다
- Dart compiler가 privacy를 강제한다.
- 더 자세한 사항은 dart.dev 사이트의 Libraries and visibility를 참고하자
- 선택후 Alt+Enter로 메뉴 불러와서
-
_ChatScreenState에TextEditingController추가하기- Tip : Flutter framework API의 소스 코드 definition을 보는 것이 뒤편에서 무슨 일이 일어나는지 이해하는데 유용할것이다
- 이것은 쉽게 할수있는데… 에디터 창에서 class나 method name 을 select하고..
- 오른쪽 클릭해서
Go to... Declaration을 메뉴에서 선택한다 - OS에 따라,
Command키나Control버튼을 클릭할수도 있다. - more options and keyboard shortcuts를 참조하자
- 오른쪽 클릭해서
- 이것은 쉽게 할수있는데… 에디터 창에서 class나 method name 을 select하고..
- Tip : Flutter framework API의 소스 코드 definition을 보는 것이 뒤편에서 무슨 일이 일어나는지 이해하는데 유용할것이다
-
- 이제 app이 state를 관리할 수 있는 능력이 생겼기에,
_ChatScreenStateclass 에 input field 와 send button을 넣으면 된다-
_ChatScreenState에_buildTextComposerfunction 을 추가한다 - 👁🗨 Observations
- Flutter에서는, widget의 stateful data는
State객체에 encapsulated 된다-
Stateobjects는 그리고 나서StatefulWidgetclass를 확장한 widget가 associated 된다
-
- 위 코드는
_buildTextComposer()라 불리는 private method를 정의하는데- 이 method는 설정이 적용된(configured)
TextFieldwidget을 탑재한Containerwidget을 return 한다
- 이 method는 설정이 적용된(configured)
-
Containerwidget에는 screen의 edge와 input field의 각 side간의 horizontal margin 설정이 추가된다 -
EdgeInsets.symmetric에 전달된 단위(units)는 ,- device의 pixel ratio에 의존적인, 특정 숫자의 physcical pixels로 번역된 logical pixels 이다
- 당신은 아마도 Android 용어(density-independet pixels1)나 iOS의 용어(points)에 익숙할 것이다
-
onSubmitted속성은 private callback method,_handleSubmitted()를 제공한다.- 처음에 이 method는 단지 field 를 clear 하는 기능만 있지만,
- 나중에 chat message를 send하는 기능을 추가할 것이다
-
TextEditingController의TextField는 text field에 대한 관리기능을 제공한다.- 이 controller는 field를 clear 하고 값을 읽어온다
- Flutter에서는, widget의 stateful data는
-
- 이것은 mutable state를 갖는
Add a text composer widget
- 👁🗨 Observations
-
_buildTextComposermethod는 text input field를 encapsulates 하는 widget을 return 한다 -
body속성에_buildTextComposer를 추가하여 app이 text input하는 user control을 보여주도록 한다
-
Add a responsive Send button
- 코드작성>
_buildTextComposer함수 내에서,Row:내부에TextField를 넣는다 - 코드작성>
TextField를Flexiblewidget으로 감싼다- 여기서 Alt+Enter를 눌러 Wrap with widget 자동완성을 이용해본다
- 👁🗨 Observations
-
Row를 이용하여 Send 버튼을 input field에 가까이 둘 수 있게 한다 -
TextField를Flexiblewidget으로 감싸는 것은-
Row가 text field의 size를 자동조절하여 - 버튼에 의해 사용되지 않는 남은 공간을 사용하도록
Row에게 알려준다
-
- 오른쪽 bracket 다음에 comma를 추가하여 fommatter가 어떻게 code를 format할 지 알려준다
-
- 다음으로, Send 버튼을 추가한다.
- 이 것은 Material app이므로, 대응되는 Material icon ▶ 을 사용한다
- Tip: 표준 Material Design icon의 목록은
- Material Icons 사이트와 Icons class 의 상수값들을 참고한다
- 코드작성>
Row에 Send 버튼을 추가한다- 👁🗨 Observations
-
IconButton이 Send 버튼을 display 한다 -
icon속성이 Material library로 부터Icons.send상수를 지정하여, 새로운Icon인스턴스를 생성한다 -
Containerwidget 안에IconButton을 위치시켜서 버튼의 margin spacing을 조절할수 있게 한다- 이렇게 하면 당신의 input field 옆에서 좀더 visually fit 해보인다
-
onPressed속성은 익명함수를 사용하여_handleSubmitted()method를 호출하공-
_textController를 이용하여 message 내용을 넘긴다
-
- Dart 에서, arrow 문법 ( => 표현식) 은 때때로 함수를 선언하는데 사용된다
- 이것은
{ return expression; }의 단축 표현으로 오직 one-line 함수에만 사용된다 - 익명과 중첩 함수를 포함하여 Dart 함수 지원에대한 개요를 보려면, Dart Langauge Tour를 참고하라
- 이것은
-
- 👁🗨 Observations
- 버튼의 컬러는 black인데, 이것은 default Material esign theme에서 왔다.
- app에 accent 컬러를 주기위해서,
IconButton에 color argument를 pass하거나, 다른 theme을 적용해라
- app에 accent 컬러를 주기위해서,
- 코드작성 >
_buildTextComposer()에서,Container를IconTheme으로 감싸라- 👁🗨 Observations
- Icons는,
IconTheme으로부터 color,opacity,size를 상속받는데,- (IconTheme widget은) 이런 chracteristics를 정의하기 위해
IconThemeData객체를 이용한다
- (IconTheme widget은) 이런 chracteristics를 정의하기 위해
-
IconThemes의data속성은 현재 them의ThemeData객체를 지정한다- 이것은 버튼(과 widget tree의 모든 다른 icon들)에 현재 theme의 accent color를 준다
-
BuildContext객체는 app의 widget tree의 한 widget의 lcoation에 대한 handle 이다- 각각의 widget은 자신만의
BuildContext를 가지는데,- (BuildContext 가)
StatelessWidget.build나State.build에 의해 return된 widget의 parent가 된다
- (BuildContext 가)
- 이것은
_buildTextComposer()가, 그것의 encapsulatingstate로 부터BuildContext객체에 access할 수 있다는 것을 의미한다 - 때문에, context 를 method에 명시적으로 넘겨줄 필요가 없다
- 각각의 widget은 자신만의
- Icons는,
- 👁🗨 Observations
6. Debug your app
- app을 debug 하기 위한 몇가지 방법이 있다
- IDE에서 바로 breakpoints를 설정할 수도 있지만,
- Dart DevToos 를 사용할 수도 있다 (Chrome DevTools과 헷갈리지 말자)
- 이번 codelab은 Android Studio와 IntelliJ를 이용해 어떻게 breakpoint를 잡는지 보여준다
- VS Code 같은 다른 editor를 사용한다면 DevTools로 debugging 해라
- Dart DevTools에 대한 친절한 소개를 원한다면, Write your first Flutter app on the web의 Step 2.5를 참조하라
- Anddroid Studio와 IntelliJ IDE로 emulator, simulator, device 에서 실행중인 app을 디버깅할 수 있다
- 이 에디터로 아래 일들을 할수 있다:
- 앱을 디버깅할 device나 simulator 선택하기
- console message 보기
- breakpoint 설정하기
- 실행시간에 변수를 조사하거나 표현식을 평가하기(evaluate expressions)
- Tip: 디버깅을 좀더 공부하려면 Debugging Flutter apps 를 참조하라
- Android Studio와 IntelliJ 에디터는 앱이 실행중일때 system log를 보여주고,
- breakpoint를 설정하고 execution flow를 조정할 수 있도록 Debugger UI를 제공한다
Work with breakpoints
- 코드작성 > breakpoint로 Flutter app 디버깅하기
- 간단하게 breakpoint 잡고 멈춰보는 것 까지만 실습
7. Add a UI for displaying messages
- 기본 app scaffolding과 화면이 준비되었다. 이제 chat message를 보여줄 영역을 정의한다
chat message 목록을 구현한다
- 이번 section에서는, (여러개의 작은 widget을 생성하고 조합하는 방식인) composition으로 chat message를 보여주는 widget을 만든다
- 한 개의 chat message를 보여주는 widget 부터 시작한다
- 그 다음, 이 widget을 중첩하여 부모 scrollable list로 넣는다
- 마지막으로, 이 scrollable list를 기본 app scaffold에 넣는다
- 코드작성 >
ChatMessagestateless widget을 추가한다: - 코드작성 >
Row를ChatMessage의build()method에 추가 한다:- 이 시점에서 분석기는 정의안된
_name만 불평해야 한다. 바로 고쳐본다 - 코드작성 >
_name변수를 정의한다- 각 chat message를 보낸이의 이름으로 label 하려는 목적이다
- 보통 사용자의 이름은 atehntication을 통해 가져오지만
- 간단한 테스트 앱 작성을 위해 hard-code한다
- 이 시점에서 분석기는 정의안된
- 👁🗨 Observations
-
ChatMessage의build()method는Rowwidget을 return 하는데-
Rowwidget은 간단한 graphical 아바타를 보여줘서 누가 chat message를 보냈는지 알려준다 -
Columnwidget은 보낸사람 이름과, text message를 가진다
-
-
CircleAvatar는 사용자의 첫번째 이니셜로 구분이 되도록 한다- 이를 위해,
_name변수의 첫번째 character를 childTextwidget 으로 전달한다
- 이를 위해,
-
crossAxisAlignment파라미터는Rowconstructor 안에서CrossAxisAlignment.start로 지정한다- 아바타와 message를 부모 widget과 상대적인 위치에 놓기 위함이다
- 아바타의 부모 widget은
Row이고 main axis가 horizontal 이라서-
CrossAxisAlignment.start는 수직축을 따라 가장 높은 위치로 설정한다
-
- message의 경우 부모 widget은
Column이고 main axis가 vertical 인데-
CrossAxisAlignment.start는 수평축을 따라 가장 왼쪽 위치로 설정한다
-
- 아바타 다음에, 두 개의
Textwidget이 수직으로 정렬되어 있어서- 위쪽은 보낸사람 이름, 아랫쪽은 text message가 위치한다
-
Theme.of(context)는 해당 앱의 기본 flutterThemeData객체를 제공한다- 나중에 나오는 step에서, Android 와 iOS에서 다르게 앱을 스타일링한다
-
ThemeData의textTheme속성은headline4와 같은, text를 위한 Material Design logical 스타일 에 대한 access를 제공한다- 이 때문에, font size나 다른 text 속성을 hard-coding 하는 일을 피할 수 있다
- 이 예제에서는, 보낸사람 이름을 message text보다 크게 설정했다
-
UI에 chat message 목록을 구현한다
- 다음 refinement는 chat messages의 목록으 가져와서 UI에 보여주는 것이다
- 사용자가 메세지 이력을 볼수 있도록 이 목록을 scrollable 하도록 만들고 싶을것이다
- 이 목록은 또한 메시지를 시간순으로 표시되어야 한다
- 또한 가장 최근 메시지가 보여지는 목록중 가장 아랫쪽에 배치되어야 한다
- 코드작성 >
_messageslist를_ChatScreenState에 추가한다 - 코드작성 >
_ChatScreenState의_handleSubmitted()method를 변경한다 - 코드작성 > 내용 전달이후 포커스를 text field로 다시 가져오기 구현
- 👁🗨 Observations
- 목록의 각 item은
ChatMessageinstance 이다 - 목록은 empty 상태로 초기화된다
-
_messages를 변경하기 위해setState()를 호출하면, widget tree의 이 부분이 바뀌었다는 것을 framework가 알게된다- 그래서 framework은 UI를 rebuild 할 필요가 있게된다
-
setState()에서는 동기적인(synchronous) operations만 수행되어야 하는데,- 그렇지않으면 framework이 operation이 끝나기전에 widget들을 rebuild할 수 있기 때문이다
- State 객체의 internal state에 많은 변경을 더할때,
- 모든 변경을 한 번의
setState()호출에 결합하는것이 좀더 일반적인 사용법이라 할 수있다.
- 모든 변경을 한 번의
- 일반적으로,
setState()호출의 outside에서 일부 private data를 변경한 후에-
setState()를 empty closure와 함께 호출하는 것이 가능하다 - 하지만,
setState의 closure내부에서 데이타를 업데이트하는 것이 선호되는데,- 이렇게 함으로써, 이후에 이것을 호출해야하는 것을 잊지 않을 것이다
-
- 목록의 각 item은
message list를 위치 시키다
- 당신은 이제 chat message 목록을 보여줄 준비가 다 되었다.
-
ChatMessagewidget에서_messageslist를 가져와서,ListViewwidget에 넣고 scrollable list로 만들자 - 코드작성 >
_ChatScreenState의build()method 안에서,Column안에ListView를 추가하라 - 👁🗨 Observations
-
ListView.builderfactory method는, list의 item당 한 번식 호출되는 함수를 제공하여 on demand로 list를 빌드한다- 그 함수는 호출때 마다 새로운 widget을 반환한다
- builder 또한 자동으로 그
childrenparameter의 mutation을 감지하고 rebuild를 시작한다
-
ListView.builder생성자로 넘어가는 parameter들은 list 내용과 외관을 customize한다 -
padding은 message text 주변에 공백을 생성한다 -
itemCount는 list내에서 메시지 숫자를 특정한다 -
itemBuilder는[index]내의 각 widget을 build하는 함수를 제공한다.- 현재의 build context가 필요하지는 않기 때문에,
IndexedWidgetBuilder의 첫번째 argument는 무시해도 된다 - 해당 argument를 underscore(_)만으로 naming하는 것은 해당 argument가 사용되지 않을것을 가리키는 convention이다
- 현재의 build context가 필요하지는 않기 때문에,
-
Scaffoldwidget의body속성은 , 이제 input field와 Send 버튼 뿐만아니라 incoming 메시지의 목록또한 포함한다- layout은 아래의 widget들을 포함한다
-
Column: 직계 childrent을 수직적으로 배치한다.Column위젯은 (Row와 마찬가지로) child widgets의 목록을 가져오는데- (child widget)은 scrolling list와 input field의 한 줄이 된다
-
ListView의 부모로서의Flexible: framework에게 말해서, 받은 메시지들로Column을 채운다. 이때TextField는 고정 사이즈를 유지한다 -
Divider: 메시지를 표시된 UI 와 메시지를 작성하는 text input들 사이에 수평선을 그린다 - text composer의 부모로서의
Container: 배경 이미지, padding, margins등 다른 여러 레이아웃을 정의한다 -
decoration: 배경 color를 정의하는 새로운BoxDecoration객체를 생성한다.- 이 경우에는 기본 theme의
ThemeData객체에의해 정의되는cardColor를 사용했다 - 이것은 메시지를 작성하는 UI에 메시지 리스트와 다른 배경을 제공한다
- 이 경우에는 기본 theme의
-
8. Animate your app
- 앱에 대한 사용자 경험이 유연하고 직관적으로 만들기 위해 widget에 애니메이션을 추가할 수 있다.
- 이 section에서 채팅 메시지 목록에 기본적인 애니메이션 효과를 추가하는 방법을 배운다
- 새로운 chat 메시지를 보낼때 , 단순히 메시지를 보여주는 대신, 메시지목록을 바닥에서 위쪽으로 천천히 움직이도록 해보자
- Flutter 에서의 애니메이션은, typed value와 status(예를 들면 다음과 같은 forward, reverse, cpmpleted, and dismissed) 포함한
Animation객체에 encapsulated 되어있다- 당신은 widget에 애니메이션 객체를 붙이거나 애니메이션 객체에 대한 변경을 관찰할수도 있다
- 애니메이션 객체에 대한 변경을 기반하여, framework은 widget이 보이는 외관을 바꿀수있고 widget tree를 rebuild할 수 있다
애니메이션 controller를 지정한다
- 애니메이션이 어떻게 동작해야하는지 지정하기 위해
AnimationControllerclass를 사용한다. -
AnimationController는 애니메이션의 중요한 특성, 플레이 시간이나 플레이 방향(forward 나 reverse0등을 정의할수 있도록 해준다 - 코드작성 >
_ChatScreenSateclass 정의를 업데이트하여TickerProviderStateMixin을 포함시킨다 - 코드작성 >
ChatMessageclass 정의 안에 animation controller를 저장할 변수를 추가한다 - 코드작성 >
_handleSubmitted()method에 animation controller를 추가한다 - 👁🗨 Observations
-
AnimationController가 애니메이션의 runtime duration을 700 milliseconds로 지정했다- 이렇게 긴 duration은 animation effect를 충분히 느리게 만들어서 애니메이션이 변화하는 과정을 관찰할수있게 해준다.
- 앱에 실제 적용할 때는 좀더 짧게 해야할 것이다
- animation controller가 새로운
ChatMessageinstance에 부착되어서, 메시지가 chat list에 추가될 때마다play forward로 동작하도록 설정되었다 -
AnimationController를 생성할 때,vsyncargument를 넘겨줘야 한다.-
vsync는 애니메이션을 앞쪽으로 진행하도록하는 heartbeats( theTicker)의 소스이다 - 이 예제는
_ChatScreenState를vsync로 사용해서,_ChatScreenStateclass 정의에TickerProviderStateMixin믹스인을 추가한다
-
- 다트에서, mixin은 class body가 multiple class hierarchies에서 재사용되도록 허용한다.
- 더 자세한 정보는 Adding features to a class: mixins 을 참고한다
-
Size Transition widget을 추가한다
- 텍스트가 미끌어져 입력될 때 점차적으로 노출되도록하는
ClipRect에 애니메이션 효과를 주도록SizeTransitionwidget을 추가한다 - 코드작성 >
ChatMessage의build()method에SizeTransitionwidget을 추가한다 - 👁🗨 Observations
-
SizeTransitionclass와 합체된CurvedAnimation객체는 ease-out(천천히 움직이는?) 애니메이션 효과를 나타낸다- ease-out 효과로 인해 메시지는 애니메이션 초기에 빠르게 slide up 되어다가 멈출때까지 slow down 된다
-
SizeTransitionwidget은 텍스트가 slide in 할때 좀 더 텍스트를 노출해주는ClipRect애니메이팅하는 동작을 한다
-
- Tip
- 만약에 hot reload로 앱을 동작시키면 , red screen을 보게 될 것이다.
- 왜그럴까? hot reload는 당신의 앱의 state를 저장한다.
- 이 경우에 , 만약 당신이 기존 chat message 목록에 조금이라 메시지를 입력했다면, 이 메시지가 저장되었다는 것을 의미한다
- hot reload가 앱을 업데이트 하려할 경우, 앞선 목록에 소급적으로 애니메이션을 콘트롤러가 적용되지 않기 때문에 , crash가 난 것이다
- hot restart가 이 문제를 해결할 수 있다.
애니메이션의 폐기
- 애니메이션 controller를 폐기해보는 것은 , 사용하던 리소스를 더 이상 사용하지 않을때 놓아주는 , 좋은 연습이 된다
- 코드작성 >
_ChatScreenState에dispose()method를 추가한다 - 애니메이션으로 좀더 실험해보고 싶다면, 시도해볼 몇가지 아이디어를 추천한다
-
_handleSubmitted()의duration값을 변경하여 애니메이션을 speed up 하거나 slow donw 해보라 -
Curvesclass에 정의된 상수를 이용하여 다른 animation curve를 테스트 해봐라 -
SizeTransition대신FadeTransitionwidget으로Container에서 fade-in animation 효과를 테스트 해봐라
-
9. Apply finishing touches
- 이번 optional step에서는, 몇가지 복잡한 디테일을 추가한단
- 예를들면 보낼 텍스트가 있는 경우에만 Send 버튼을 enable하거나
- 긴 메시지를 wrapping 하거나
- 안드로이드나 iOS에 특화한 native-looking UI를 구현하는 것이다
send 버튼을 context-aware 하도록 만들기
- 현재 보낼 텍스트가 없더라도 Send 버튼 이 enable 되어있다.
- 보낼 텍스트 존재하는지 여부에 따라 send 버튼의 모양이 바꾸고 싶을수 있다
- 코드작성 >
_isComposingprivate 변수를 추가하여 input field에서 사용자 타이핑할 때 true로 설정하도록 한다 - 코드작성 >
_ChatScreenState에onChanged()콜백 method를 추가한다 - 코드작성 >
_ChatScreenState에서onPressed()콜백 method를 업데이트한다 - 코드작성 >
_handleSubmitted를 수정하여 텍스트 필드가 비었을 경우_isComposing을 false로 설정한다 - 👁🗨 Observations
-
onChanged콜백이TextField에게 사용자가 텍스트를 수정했다가 알려준다.-
TextField는 필드의 현재 값에서 값이 변경될 때마다 이 method를 호출한다
-
-
onChanged콜백은setState()를 호출하여 필드에 텍스트가 존재한다면_isComposing을 true로 변경한다 -
_isComposing이 false 일때,onPressed속성이null로 설정된다 -
onSubmitted속성 또한 메시지 리스트에 빈 문자열을 추가하지 않도록 수정된다 - 사용자가 텍스트 필드에 문자열을 입력하면
_isComposing이true가 된다.- 사용자가 Send 버튼을 누르면 framework이
_handleSubmitted()를 invoke 한다
- 사용자가 Send 버튼을 누르면 framework이
- 사용자 텍스트 필드에 입력하지 않으면,
_isComposing은false이고- 그 widget의
onPressed속성은null로 설정되어, Send 버튼은 비활성화된다. - frameworkd이 자동적으로 버튼 color를
Theme.of(context).disabledColor로 변경한다
- 그 widget의
-
긴 문자열 줄 바꾸기 (wrap)
- UI가 표현하기에는 긴 문자열을 사용자가 입력할 때, 모든 입력된 메시지를 보이기 위해 줄 바꿈이 필요하다
- 현재는 넘치는 문자열을 잘리면서, visual overflow 에러가 나타난다.
- 줄 바꿈이 되도록하는 간단한 방법은 문자열을
Expandewidget에 넣는 방법이다 - 코드작성 >
Columnwidget은Expandedwidget 으로 감싼다 - 👁🗨 Observations
-
Expandedwidget은 자식 widget 에게 layout constraints를 가할 수 있는데…- 이 경우에는
Column의 width 에 제한을 가한다. - 여기서, 보통 콘텐츠에 의해 결정되는
Textwidget의 width에 대해 제한하고 있다
- 이 경우에는
-
Android 와 iOS 용으로 커스터마이즈
- 당신의 앱에 자연스러운 look & feel을 주기위해,
- theme의 추가하고
FriendlyChatAppclass의build()method에 간단한 로직을 추가할 수 있다
- theme의 추가하고
- 이번 step 에서, 다른 primary와 accent 컬러 세트를 적용하는 platform theme을 하나 정의한다
- 또한 Send 버튼에 대해서
- 안드로이드에서 Material Design의
IconButton을, - iOS에서는
CupertinoButton을 사용한다
- 안드로이드에서 Material Design의
- 코드작성 > 아래 코드를
main.dart의main()method 아래에 추가한다 - 👁🗨 Observations
-
kDefaultTheme ThemeData객체는 안드로이드용 컬러(purple with orange accents) 를 지정한다 -
kIOSTheme ThemeData객체는 iOS용 컬러(light grey with orange accents) 를 지정한다
-
- 코드작성 >
FriendlyChatAppclass 에서MaterialAppwidget의theme속성을 이용하여 theme을 변경한다 - 코드작성 >
AppBarwidget 의 theme을 modify한다 ( 당신 app UI의 top에 있는 banner) - 👁🗨 Observations
- top-level
defaultTargetPlatform속성과 conditional operatiors 가 theme 을 선택하기 위해 사용되었다 -
elevation속성은AppBar의 z-coordinate을 정의한다 -
4.0의 z-coordinate 값은 정의된 shadow (Android) 를 가지며,0.0값(iOS)은 shadow가 없다
- top-level
- 코드작성 > send icon을 Android와 iOS 용으로 customize 한다
- 코드작성 >
Containerwidget내의 top-levelColumn을 감싸고, 윗쪽 edge에 light grey border 효과를 준다- 이 border는 iOS에서, app bar를 app과 비주얼적으로 구분하는데 도움을 준다
10. Next steps
- Congratulations! 당신은 이제 Flutter framework으로 cross-platform mobile app을 구축하는 기본을 알게 되었다
-
What we covered
- 바닥에서 부터 Flutter app을 만드는 방법
- Android Studio 와 IntelliJ 에서 사용할 수 있는 단축키 사용법
- 당신의 Flutter app을, 에뮬레이터, 시뮬레이터, 실제 디바이스에서 실행하고, hot reload하고, 디버그하는 방법
- 인터페이스를 widget과 animation으로 customize하는 방법
- Android와 iOS에 대해 사용자 interface를 customize하는 방법
-
What’s next
- 다른 Flutter codelabs 을 시도해봐라
- Material compnents로 앱을 만드는 것에 대해 흥미가있나요?
- 5-part Material components(MDC) 코드랩 시리즈로 쇼핑앱을 만들면서 좀더 배워보세요
- Flutter에 대해 계속 배우세요
- flutter.dev : Flutter project 문서 사이트
- The Flutter cookbook
- The Flutter API reference documentation
- 추가적인 Flutter sample apps 과 source code
- 키보드 단축키에 대한 정보
- Flutter - 빠른 개발위한 IDE 단축키, Pooja Bhaumik 작성
- Flutter: 내가 좋아하는 단축키, Andrea Bizzotto 작성
11. Optional: Get the sample code
- 샘플을 레퍼런스로 보고거나 코드랩의 특정 section부터 시작하고 싶어서 샘플 코드를 다운로드 받고 싶을수 있다
- 코드랩의 샘플코드를 다운받으려면 터미널에서 아래 명령을 입력하라
1
> git clone https://github.com/flutter/codelabs - 이 코드랩의 샘플 코드는
friendly_chat폴더에 있다.- 각각 번호가 붙혀진 단계별폴더에는 각 단계의 최종 코드를 볼 수있다.
- 각 단계별 어느 코드라도
lib/main.dart에서 가져와서DartPad instance에 넣고 실행시켜볼 수있다
TroubleShooting
Flutter Doctor Fail
- Android Studio를 Bumblebee로 업데이트 했더니 다음과 같이 에러가 날 경우
- 얼마전에 Windows 11으로 업데이트 했다가 다시 Windows 10으로 복구했을때 초기화 되었을 수 있다..
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel beta, 2.3.0-24.1.pre, on Microsoft Windows [Version 10.0.19044.1466], locale ko-KR)
[!] Android toolchain - develop for Android devices (Android SDK version 30.0.0)
X cmdline-tools component is missing
Run `path/to/sdkmanager --install "cmdline-tools;latest"`
See https://developer.android.com/studio/command-line for more details.
X Android license status unknown.
Run `flutter doctor --android-licenses` to accept the SDK licenses.
See https://flutter.dev/docs/get-started/install/windows#android-setup for more details.
[√] Chrome - develop for the web
[√] Android Studio (version 4.2.0)
[√] Connected device (2 available)
! Doctor found issues in 1 category.
해결책
- 안드로이드 스튜디오를 설치했을경우 , Tools ▶ (중간쯤) SDK Manager ▶ (대화창 가운데탭) SDK Tools ▶ (3번째쯤) Android SDK Command-line Tools (latest) 체크
- Apply & OK
- 이제
flutter doctor패스함1 2 3 4 5 6 7 8 9
╰─ flutter doctor Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel beta, 2.3.0-24.1.pre, on Microsoft Windows [Version 10.0.19044.1706], locale ko-KR) [✓] Android toolchain - develop for Android devices (Android SDK version 30.0.0) [✓] Chrome - develop for the web [✓] Android Studio (version 4.2.0) [✓] Connected device (2 available) • No issues found!