[Flutter] 튜토리얼 앱 만들기

     

공식 홈페이지 튜토리얼.

스타트업의 이름을 랜덤 하게 지어주는 앱을 만들기로 한다.

공심 홈피 링쿠 - flutter-ko.dev/docs/get-started/codelab

대략 이런 리스트 뷰 앱인것 같다

 

일단 이름을 지어주기 위해서 english_words라는 패키지를 설치해야 한다.

 

flutter에서 외부 라이브러리는 pubspec.yaml에 관리되고 있다. pubspec.yaml에 가보면 dependencies: 아래 기본적으로 몇 가지 패키지가 적혀있는데, 그 아래 english_words: ^4.0.0-0을 추가하자.

 

그리고 터미널에서 flutter pub get을 입력하면 .yaml에 입력해놓은 것들을 다운받는다. 마치 장고에서 pip install -r requirements.txt를 입력하는 것과 비슷하다.

 

이제 import 'package:english_words/english_words.dart' 를 통해 Word Pair라는 객체를 쓸 수 있는데, 이게 아마도 아무 영어 단어나 쌍으로 묶어주는 객체인 것 같다. 

 

flutter도 react처럼 상태(state)를 관리하는 것처럼 보인다. 아래 코드를 보면 State를 먼저 만들고 State를 보여주는 Widget을 만드는 순서로 코딩이 되어있다.

 

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

void main() => runApp(MyApp());

class RandomWords extends StatefulWidget{
  @override
  State<StatefulWidget> createState()=> _RandomWordsState();
}

class _RandomWordsState extends State<RandomWords>{
  final _suggestions = <WordPair>[];
  final _saved = <WordPair>{};
  final _biggerFont = TextStyle(fontSize: 18.0);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Startup Name Generator'),
      ),
      body: _buildSuggestions(),
    );
  }

  Widget _buildSuggestions() {
    return ListView.builder(
      padding: EdgeInsets.all(16.0),
      itemBuilder: (context, i) {
        if (i.isOdd) return Divider();

        final index = i  ~/ 2; //???

        if (index >= _suggestions.length){
          _suggestions.addAll(generateWordPairs().take(10));
        }
        return _buildRow(_suggestions[index]);
      });
  }

  Widget _buildRow(WordPair pair){
    final alreadySaved = _saved.contains(pair);
    return ListTile(
      title: Text(
        pair.asPascalCase,
        style: _biggerFont,
      ),
      leading: Icon(
        alreadySaved ? Icons.favorite : Icons.favorite_border, color: alreadySaved ? Colors.red : null,
      ),
    );
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context){
    return MaterialApp(
      title: 'Welcome',
      home: RandomWords(),
    );
  }
}

 

실제로 앱을 실행하면 가장 먼저 실행되는 건 void main()이다. 화살표 연산자(=>)로 runApp을 실행하고 MyApp() class를 실행하도록 되어있다. MyApp 안에는 RandomWords class를 호출하고, RandomWords는 _RandomWordState를 호출해서 결론적으로는 WordPair에 있는 텍스트로 구성되어있는 ListTile ListView를 반환한다.

 

지금 위에 있는 코드를 실행하면 리스트 왼쪽에 하트? 아이콘이 뜹니다. ㅋㅋ 이건 뭔가 증권 앱에서 관심종목? 느낌으로 favorite을 등록할 수 있는 기능을 만들려고 한다.

 

원래는 하트 아이콘이 오른쪽 끝에 있었는데 ListTile에 Icon코드 앞에를 leading으로 바꾸니까 앞으로 이동했다.

 

trailing으로 하면 뒤에온다.
leading으로 하면 앞으로 ㅋㅋ

 

튜토리얼에는 trailing으로 되어있는데 뭐 뭐 있는지 궁금해서 컨트롤 + 클릭으로 찾아가 봤더니 leading, subtitle 등등 다양한 포맷을 사용할 수 있게 되어있었다.

 

아주 친절한 설명

 

클릭 이벤트 구현

 

이게 클릭 이벤트가 맞나 ㅋㅋㅋ

안드로이드 앱에서는 onClick이벤트였겠는데, flutter에서는 onTap이다.

ListTile을 실제적으로 만드는 Widget인 _buildRow에서 onTap이라는 속성을 만들면 Tap 했을 때 이벤트를 정할 수 있다.

  Widget _buildRow(WordPair pair){
    final alreadySaved = _saved.contains(pair);
    return ListTile(
      title: Text(
        pair.asPascalCase,
        style: _biggerFont,
      ),
      leading: Icon(
        alreadySaved ? Icons.favorite : Icons.favorite_border, color: alreadySaved ? Colors.red : null,
      ),
      onTap: (){
        setState(() {
          if (alreadySaved) {
            _saved.remove(pair);
          } else {
            _saved.add(pair);
          }
        });
      },
    );

onTap을 넣고 setState()를 통해 Tap 했을 때 상태 값을 바꿔주도록 설정했다. 아마 리액트랑 똑같이 상태를 관리하니까 상태 값이 변하면 화면에 바로 적용된다. 공식 홈페이지에는 이렇게 설명되어있다.

 

Tip: In Flutter's reactive style framework, calling setState() triggers a call to the build() method for the State object, resulting in an update to the UI.

대충 setState를 하면 build()를 호출해서 화면 UI를 변경시킨다는 거지.

 

 

 

 

 

화면 이동

이제 하트를 누른 이름들을 모아서 볼 수 있는 화면을 새로 만든다. flutter에서는 화면이 스택으로 관리된다고 한다. Navigator 스택에 화면을 push 하고 pop 하면서 화면 이동을 하는 것 같다. RandomWordsState 클래스에다가 actions 속성을 추가하면 우리가 앱에서 흔히 볼 수 있는 오른쪽 위 상단바를 만들 수 있다.

 

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Startup Name Generator'),
        actions: [
          IconButton(icon: Icon(Icons.list), onPressed: _pushSaved)
        ],
      ),
      body: _buildSuggestions(),
    );
  }

 

actions가 배열로 되어있길래 3개를 넣어봤더니 아이콘이 3개가 생겼다.

 

  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Startup Name Generator'),
        actions: [
          IconButton(icon: Icon(Icons.list), onPressed: _pushSaved),
          IconButton(icon: Icon(Icons.list), onPressed: _pushSaved),
          IconButton(icon: Icon(Icons.list), onPressed: _pushSaved),
        ],
      ),
      body: _buildSuggestions(),
    );
  }

 

리스트 아이콘이 3개가 생겼다.

10개도 넣어봤는데 넣는 대로 생기네 ㅋㅋㅋㅋ

 

 

이제 실제로 화면이 이동하는걸 코드로 구현하자

  void _pushSaved(){
    Navigator.of(context).push(
      MaterialPageRoute<void>(
        builder: (BuildContext context){

          final tiles = _saved.map(
              (WordPair pair){
                return ListTile(
                  title: Text(
                    pair.asPascalCase,
                    style: _biggerFont,
                  ),
                );
              },
          );

          final divided = ListTile.divideTiles(tiles: tiles, context:context).toList();

          return Scaffold(
            appBar: AppBar(
              title: Text('saved Suggestions'),
            ),
            body: ListView(children: divided),
          );
        },
      ),
    );
  }

 

Navigator.of(context)를 하면 현재 앱의 Navigator를 불러올 수 있다. 여기에 push를 하면 아까 말한 Navigator 스택에 화면이 push 돼서 새로운 화면으로 이동할 수 있다. 근데 push를 하니까 상단바에 뒤로 가기가 자동으로 들어가는데 이건 어떻게 설정하는지 모르겠네 ?_?

 

이동 됩니다. ㅎㅎㅎㅎㅎ

 

 

테마 바꾸기

 

테마 바꾸는 건 엄청 쉬운데 MaterialApp으로 만들었기 때문에 그 안에 theme 속성을 수정해주면 된다. 

 

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context){
    return MaterialApp(
      title: 'Welcome',
      theme: ThemeData(
        primaryColor: Colors.pink
      ),
      home: RandomWords(),
    );
  }
}

 

요롷게 theme 속성을 추가하고 primaryColor를 바꿔주면 앱 기본 테마가 바로바로 바뀐다.

 

primary color pink

 

 

구글에 flutter 가이드가 잘 되어있어서 따라 하면서 공부하면 될 것 같다 ㅎㅎ

 

다음에 할 거 Layouts in Flutter - Flutter

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형

댓글

Designed by JB FACTORY