[flutter] 플러터로 첫번째 앱 만들기

in #kr5 years ago (edited)

출처 : 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개로 나눠서 하려다가 그냥 한개로 만들었네요
  • 실제 하나하나 따라가면서 학습하면서 하니 시간이 좀 걸리네요 후...
  • 궁금한 것은 언제든지 댓글 문의 바랍니다.
Sort:  

헉~~~~ 또 피곤!! ㅋㅋ 즐거운 불금 되세요^^

안피곤님이 출동 할 것입니다 / 즐거운 주말 보내세요~~ @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.

원사마님 플러터 진도가 넘 빨라요.😀👍

Coin Marketplace

STEEM 0.31
TRX 0.11
JST 0.034
BTC 64852.72
ETH 3178.07
USDT 1.00
SBD 4.20