* 플러터를 원문 공식 문서 (https://flutter.dev/docs)를 읽으면서 공부하는 과정에서 정리하고자 작성하는 포스팅으로
저는 플러터 실무 개발 경력이 없는 대학생인 점을 미리 밝힙니다.
* 추가로 오준석의 플러터 생존코딩 및 제 개인 경험을 참고하여 작성하고 있습니다.
* 오역, 오탈자, 잘못된 내용의 지적은 항상 감사히 받겠습니다 :)
지난 포스팅에서 이어, import한 모듈을 사용합니다.
Text 위젯에 들어갈 문자열을 import한 모듈을 이용해 넣어보겠습니다.
build 메소드에 final 키워드를 넣어 wordPair 인스턴스 변수를 만들고, WordPair.random() 객체를 생성합니다.
final은 상수를 만드는 키워드 입니다.
Scaffold의 body 인자에 있는 Center 앞에 const를 빼줍니다.
const 역시 final과 비슷하게 상수를 만드는 키워드입니다.
final은 변수 앞에 붙어서 '변수'를 상수로 취급하게 하지만,
const는 변수 뿐 아니라 '값'에 붙어서 '상수 값'으로 만들 수 있습니다.
Center() 도 결국 '위젯 객체'라는 값인데, 지금까지 이 값을 상수로 사용했습니다.
하지만, 런타임 시 wordPair 객체에 의해 랜덤하게 생성되는 값은
컴파일 시 상수 값을 설정하는 const에 쓸 수 없습니다.
따라서 Center 위젯객체 앞의 const 키워드를 빼주어야 합니다.
자세한 내용은
(https://dart.dev/guides/language/language-tour#final-and-const)
dart 공식 문서를 확인해보면 좋습니다.
Text 객체의 인자로 들어오는 문자열 대신 wordPair.asPascalCase 를 넣어줍니다.
구글 공식문서에서는 PascalCase에 대해서도 설명해주고 있는데 자세한 설명은 생략하겠습니다.
(간단히, 각 단어의 첫머리만 대문자로 쓰는 기법입니다.)
작성한 코드를 저장하면 아래와 같이 나옵니다.
가운데에 랜덤하게 생성된 영어 단어가 나왔습니다.
여기에서 한번 더 저장을 눌러보면 아래와 같이 다른 랜덤한 단어가 또 나옵니다.
이는 랜덤한 문자열을 생성하는 코드가 build 메소드 안에 작성되어 있는데,
build 메소드는 MeterialApp() 객체가 렌더링을 요구할 때마다 실행되기 때문입니다.
이제 StatefulWidget을 사용해보겠습니다.
우리가 지금까지 사용한 MyApp() 클래스는 StatelessWidget 을 상속받은 위젯입니다.
StatelessWidget은 내부의 값이 변하지 않는 클래스입니다.
따라서 StatelessWidget 클래스 내부의 '값'들은 모두 상수입니다.
변수를 가진다고 해서 컴파일 에러를 일으키지는 않습니다.
(클래스가 변수를 갖는 것이 문법적 오류는 아니니까요)
다만 안드로이드 스튜디오에서 경고를 띄워줍니다.
StatefulWidget은 이 위젯의 수명동안 바뀔 수 있는 '상태 (state)'를 갖고 있습니다.
StatefulWidget을 구현할 때는 적어도 아래의 2개의 클래스를 가져야 합니다.
1. StatefulWidget
2. State
StatefulWidget 클래스는 State 클래스의 객체를 생성합니다.
이 클래스는 그 자체로는 '변하지 않는 성격'을 갖고 있으며,
삭제되었다가 재생성될 수 있습니다.
따라서 '변할 수 있는 내용'은 이 클래스가 아닌 State 클래스에서 구현합니다.
State클래스는 위젯의 수명동안은 계속해서 존재합니다.
이제 RandomWords 라는 이름의 Stateful Widget을 만들어보겠습니다.
기존 코드 아래에 이어서 stful을 쳐봅니다.
안드로이드 스튜디오가 새로 제안을 띄웁니다.
이걸 클릭하면 stateful widget 클래스와 state 클래스의 기본 틀을 알아서 만들어줍니다.
이제 빨간색 네모 안에 클래스 이름을 적어주면 아래 클래스 이름에도 알아서 똑같이 적어집니다.
RandomWords를 적어보겠습니다.
State클래스를 상속받는 클래스의 이름 앞에는 언더스코어 (_)가 있는데,
dart 언어에서 State 클래스 객체를 위한 추천 방법이라고 하네요.
또한 우리가 사용하는 State 클래스는 RnadomWords 클래스만을 위한 State로서
제네릭 State 클래스를 생성함을 알 수 있습니다.
이제 이 State 클래스는 RandomWords 위젯을 위한 상태 (State)를 나타내는 역할을 하며,
대부분의 코드는 이 State 클래스 내부에 기술하게 됩니다.
이제 이 클래스에서 단어 리스트를 저장할 겁니다.
그리고 리스트 뷰를 사용해 사용자가 스크롤을 내릴 때마다
계속해서 단어를 계속 보여주도록 하겠습니다.
그리고 사용자가 마음에 드는 단어를 찾으면, 하트아이콘을 클릭해 해당 단어를 저장하거나
저장한 단어를 지우는 것도 만들어보겠습니다.
State 제네릭 클래스의 build 메소드를 아래와 같이 작성합니다.
class _RandomWordsState extends State<RandomWords> {
@override
Widget build(BuildContext context) {
final wordPair = WordPair.random();
return Text(wordPair.asPascalCase);
}
}
낯이 익은 코드네요.
기존의 StatelessWidget 클래스의 build 메서드 내부 코드를 아래처럼 수정합니다.
기존 WordPair 객체를 제거하고, RandomWords 객체를 Center 위젯의 child로 넘겨주었습니다.
이제 프로젝트를 저장하고, 앱의 reload를 관찰하면 아까와 같은 디자인의 앱임을 알 수 있습니다.
하지만 내부에서 사용하는 위젯이 StatelessWidget 에서 StatefulWidget으로 바뀌었습니다.
이제 계속해서 스크롤이 늘어나는 List View를 만들어보겠습니다.
List View의 Builder 생성자는 필요에 따라서 리스트를 계속 추가합니다.
우선 State 클래스 안에
_sugguestions 라는 이름의 WordPair 객체 리스트와
폰트사이즈를 상수값으로 저장할
_biggerFont 변수를 선언합니다.
다음으로 _buildSuggestions() 메소드를 아래와 같이 작성합니다.
이 메소드는 단어를 보여줄 리스트뷰 위젯을 생성합니다.
padding 인자는 위젯 내부에 만드는 여유공간 입니다.
위 코드는 16.0 만큼의 padding을 위젯의 상하좌우 모든 면에 똑같이 적용하는 코드입니다.
ListVIew.builder() 는 itemBuilder를 인자로 가지는데,
이는 익명함수로 된 콜백 함수를 인자로 받습니다.
* dart 문법에서 익명함수는 (매개변수1, 매개변수2, ...,) { 함수 구현부 } 처럼 되어 있습니다.
(주석 1번)
itemBuilder가 갖는 익명함수에는 2개의 값이 전달됩니다.
첫번째는 BuildContext, 두번째는 row iterator 입니다.
row iterator는 0에서 시작해, 이 함수가 호출 될 때마다 값을 1씩 늘려나갑니다.
위 코드에서는 context, i 라는 두 매개변수의 형태로 이 두 값을 받습니다.
itemBulider 콜백은 WordPair 객체마다 한번씩 호출되며, 이 객체를 ListTile row에 배치합니다.
(주석 2번)
만약 현재 열이 홀수번째 열이라면
구분선을 긋기 위해 Divider() 객체를 리턴하여 리스트뷰에 배치합니다.
(주석 3번)
인덱스를 2로 나눈 몫을 가져옵니다.
* 다트 문법에서는 ~/ 연산자가 몫을 계산하는 연산자입니다.
ListTile과 구분선 두개씩 묶어서 하나의 WordPair 객체로 보는 것입니다.
즉 index를 2로 나눈 몫은, 현재까지의 WordPair객체 숫자와 같습니다.
(주석 4번)
만약 현재 WordPair객체 숫자가, WordPair를 저장하는 리스트 사이즈를 넘었다면
WordPair를 저장하는 _suggestions 리스트에 10개의 단어를 더 만들어 넣습니다.
마지막으로 _buildRow() 함수를 호출하여 리스트뷰에 이 Row를 배치합니다.
아직 _buildRow() 함수는 만들지 않았기 때문에, 이 함수는 따로 구현해야 합니다.
_buildRow() 함수는 인자로 받은 이름을 가지고 ListTile 위젯을 만드는 역할을 해줄 것입니다.
_buildRow() 함수를 아래와 같이 작성합니다.
ListTile의 title 인자는 각 타일에 표시할 문자열을 나타내는데, Text() 위젯으로 넣습니다.
Text위젯은 문자열을 기본 인자로 갖고,
style 인자를 추가로 가질 수 있습니다. (TextStyle() 위젯을 넣습니다.)
아까 위에서 만든 TextStyle 위젯을 넣어줍니다.
이제 아까 build메소드에서 직접 Text() 위젯을 반환하도록 했던 코드를
우리가 지금까지 작성한 ListView 위젯을 반환하도록 하는 코드로 수정합니다.
다만, ListView를 직접 반환하는 것이 아닌, Meterial 디자인을 가진 앱의 형태를 띄어야 하므로
Scaffold() 위젯을 반환하고, 그 안에 ListVIew를 넣는 형식으로 반환해야 합니다.
그리고 마지막으로 MyApp() 클래스에서 Scaffold() 를 반환하는 대신,
우리가 만든 StatefulWidget을 반환하도록 하면 끝입니다.
아래와 같이 코드를 수정합니다.
결과적으로는 이 RandomWords() 클래스도 build 메소드로 Scaffold() 위젯을 반환하니
Scaffold()를 직접 넣은 것과 비슷하겠지만,
차이점은 StatefulWidget 이라는 점입니다.
이제 앱을 리로드해보겠습니다.
이렇게 이름들 목록이 생성됩니다.
또 Divider는 각각의 ListTile 사이에 있는 회색선입니다.
스크롤을 내리면 추가로 이름이 나타나며,
이는 무한정 (리소스의 한계로 정말 무한대는 아닙니다.) 계속해서 이름을 생성합니다.
다음 포스팅에서는 각각의 이름에 하트 아이콘을 클릭하여
내가 원하는 이름을 저장하는 기능을 구현해보겠습니다.
'Android > Flutter' 카테고리의 다른 글
[Flutter] 2. 플러터의 위젯 & MaterialApp, Scaffold, AppBar 위젯 (0) | 2021.07.05 |
---|---|
[Flutter] 1. 플러터로 만드는 첫 번째 앱 (4) - 새 창에 저장한 이름 보여주기 (0) | 2021.07.03 |
[Flutter] 1. 플러터로 만드는 첫 번째 앱 (3) - ListTile에 아이콘을 추가하여 이름 저장하기 (0) | 2021.07.02 |
[Flutter] 1. 플러터로 만드는 첫 번째 앱 (1) - 플러터 앱의 구조와 외부 라이브러리 사용 (0) | 2021.06.30 |
[Flutter] 0. 플러터 설치 (0) | 2021.06.30 |