본문 바로가기

Flutter/개발일지

[Flutter/개발 일지 2] Write your first app 무작정 해석하며 따라하기

2번째 일지 22년 03월 04일

수업 시간에 간략하게 설명해주신 코드를 다시 차근차근 보면서 스스로 해석해보는 시간을 가졌습니다.

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

 

Write your first Flutter app, part 1

How to write a web-based app in Flutter.

docs.flutter.dev



STEP 1


계속해서 값이 변하고 그것을 나타내야 하는 부분이 없기 때문에

StatelessWidget으로 클래스를 선언한 것은 이제 자연스럽습니다.

 

뒤에 Scaffold를 이용해 앱바와 Center를 맞춰주는데

저 Center가 엄청 혁명적인 게 창의 크기가 어디에 있던 센터를 딱 맞춰줍니다.

예전에 CSS로 무작정 맞출 때는 정말 화딱지 났던 작업인데 그냥 한 줄로 된다니... 혁명입니다.



Step 2: Use an external package


대충 외부 패키지를 프로젝트로 끌고 올 때 pub.dev에 있는 것들이라면 한 줄로 끌어올 수 있다는 의미인 것 같습니다.

 

단 두 줄을 입력함으로써 외부 패키지 추가가 완료되었고

상단에 import package를 하며 본격적으로 사용이 가능하였습니다.

 

As you type, Android Studio gives you suggestions for libraries to import. It then renders the import string in gray, letting you know that the imported library is unused (so far).

가져왔을 때 주석처럼 회색 처리가 되어있어서 이게 뭐지? 하고 생각했었는데

플라터 Docs에 의하면 import 된 library가 사용되지 않으면 회색으로 처리된다고 하더군요.

JAVA에서 import 하고 사용하지 않는 library에 노란 밑줄이나 전구 표시가 뜨는 것과 비슷한 것 같습니다.

 

파란 박스를 해석하자면 파스칼 케이스가 낙타 등처럼 맨 앞글자만 크게 만드는 것과 같다고 되어있다.

이미지를 보면 final로 string을 생성하고 const를 삭제할 대 final과 const의 역할이 같아서 그런가 보다 하고 넘어갔는데

그렇다고 final 부분에 const를 넣으니 실행되는 것도 아니라서 조금 더 공부해보고 내용을 추가해야겠습니다.


3/7 Dart Docs에서 찾아보니 인스턴스 변수에는 const를 사용할 수 없다고 하는데

이것은 다른 페이지에서 설명할 Null Safety와 관련이 있습니다.

 



Step 3: Add a Stateful widget


import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class RandomWords extends StatefulWidget {
  const RandomWords({ Key? key }) : super(key:key) ;
  @override
  _RandomWordsState createState() => _RandomWordsState() ;
}

class _RandomWordsState extends State<RandomWords> {
  @override
  Widget build(BuildContext context) {
    final wordPair = WordPair.random() ;
    return Text(wordPair.asPascalCase) ;
  }
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @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: RandomWords(),
        ),
      ),
    );
  }
}

여기서는 StatefulWidget에 대해서 다루는 파트입니다.

상태가 변하는 widget을 사용하고 다루기 위해서는 2개의 클래스가 필요합니다.

StatefulWidget을 통해서 생성된 클래스는 계속해서 유지되지만 StatefulWidget은 변경하거나 폐기할 수 있습니다.



Step 4 : Create an infinite scrolling ListView


이번에는 무한 스크롤을 할 수 있도록 하는 것을 진행했습니다.

ListView.builder를 이용하게 되면 제가 일일이 리스트를 만드는 게 아니라 동적으로 생성하는 게 가능해집니다!

 

먼저_suggestions라는 WordPair를 담을 수 있는 list를 추가합니다.

_biggerFont라는 폰트 크기를 조절하는 변수도 추가합니다.

코드에 보이는 /*1*/ ~ /*4*/를 Doc에서 영어로 상세히 설명하고 있는데 한국어로 풀어보자면

 

1. itemBuilder 익명 함수(anonymous function)

플라터에서는 이 클래스 내부에서만 잠깐 사용할 함수의 경우 따로 함수 이름을 지정하지 않고 사용이 가능합니다.

함수를 통해서 리스트에 아이템을 넣고 구분선을 만듭니다.

 

2. If 조건문

왼쪽 사진은 if 조건문이 없을 때이고 오른쪽이 정상적으로 구동하는 사진인데

단어를 pair로 가져올 때마다 ListTile row에 단어 쌍을 배치하는데

짝수일 경우에는 리스트에 아이템을 추가하고 홀수 일 때는 구분선을 추가하는 조건문입니다.

 

3. i ~/ 2

i를 2로 나누었을 때 결과를 i값으로 가집니다.index가 각각 1,2,3,4,5 일 때면 i의 값은 0,1,1,2,2 가 됩니다.

 

4. 조건문

사실 이 조건문이 무한 스크롤의 핵심입니다!!

이 조건문을 통해서 더 이상 스크롤할 수 없을 때 새로운 10개를 가져와서 리스트에 추가하는 조건문입니다.

// Copyright 2018 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:english_words/english_words.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class RandomWords extends StatefulWidget {
  const RandomWords({ Key? key }) : super(key:key) ;
  @override
  _RandomWordsState createState() => _RandomWordsState() ;
}

class _RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[] ;
  final _biggerFont = const TextStyle(fontSize: 18.0) ;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Startup Name Generator'),
      ),
      body: ListView.builder(
        padding: const EdgeInsets.all(16.0),
        itemBuilder: /*1*/ (context, i) {
          if(i.isOdd) return const Divider() ; /*2*/

          final index = i ~/ 2 ; /*3*/
          if(index >= _suggestions.length) {
            _suggestions.addAll(generateWordPairs().take(10)) ;/*4*/
          }
          return ListTile(
            title: Text(
              _suggestions[index].asPascalCase,
              style: _biggerFont,
            ),
          ) ;
        }
      ),
    ) ;
  }
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {

    return const MaterialApp(
      title: 'Startup Name Generator',
      home: RandomWords(),
    );
  }
}

코드 보시며 참조하시면 좋겠습니다 :)

참고로 얼핏 보이는 변수 앞에 _(언더바)는 플라터에서 private으로 선언할 때 사용한다고 합니다.

따로 위에 선언 부분으로 가서 내가 private으로 했는지 public으로 했는지 찾을 필요 없게 만든 것 같은데 편리하네요.

 

아래는 완성본입니다.