Flutter 정리

최기환·2023년 4월 13일
0

Flutter

목록 보기
1/2

플러터란?

구글에서 개발한 크로스 플랫폼 프레임워크.
Dart언어를 기반으로 만들어졌다.

설치

https://docs.flutter.dev/get-started/install/windows
위 링크를 통해 SDK를 다운 받는다.

Dart 언어 정리

Dart는 기본적으로 Null safe 언어이다.

변수

var name = "Hellow World";
var year = 1977;
var antennaDiameter = 3.7;
var flybyObjects = ['Jupiter', 'Saturn', 'Uranus'];
var image = {
	'tags': ['saturn'],
    'url': 'www.naver.com',
};
String name = 'Bob';
int number = 0;
int? linCount; // 기본적으로 모든 변수가 Null값을 가질 수 없지만 ? 연산자를 통해 Null값이 할당되어질 수 있도록 할 수 있다.
double y = 1.1;
// int 와 double을 더할 수 있다.
List<int> numArr = [1, 2, 3];
final name = 'Bob'; 
final String nickName = 'Bobby';
// final로 선언하면 재할당이 금지된다.
const bar = 1000000; // 상수 타입. final이랑 비슷하지만 컴파일 단계에서 인식되기 때문에 반드시 선언과 초기화가 동시에 이루어져야 한다.
  • 배열이나 객체의 마지막 요소 끝에 , 를 항상 붙여줌.(안붙여도 상관없다)
  • var 키워드로 선언한 변수에는 어떤 타입의 값이든 할당 가능하지만 var 키워드의 변수를 초기화 하고 나면 변수 타입이 지정되어서 다른 타입의 값을 재할당 할 수 없다. 같은 타입의 값만 할당 가능해진다.

타입

  • int, double
  • String
  • bool
  • List
  • Set
  • Map
  • Null
    가 있다.

조건문

다른 언어들의 조건문과 똑같다.

if (year >= 2001) {
  print('21st century');
} else if (year >= 1901) {
  print('20th century');
} else {
  print('something');
}

함수

int fibonacci(int n) {
  if (n == 0 || n == 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

var result = fibonacci(20);

클래스

class Person {
  String name;
  int age;
  
  Person(String name, int age) {
  	// 초기화 코드
    this.name = name;
    this.age = age;
  }
  
  // 메소드
  void printSomething() {
    print('Hello ${name}'); // 템플릿 문자열
  }

비동기 처리

asinc await를 사용하는데 해당 함수 앞에 Future<타입>을 붙여줘야 한다.

Future<void> checkVersion() async {
  var version = await lookUpVersion();
}

플러터 정리

시작

VsCode 명령 팔레트에 > New Project를 입력해서 시작 할 수 있다.
New EmptyApplication으로 프로젝트를 시작하면 다음과 같은 폴더가 만들어진다.

주로 코드를 변경하고 추가할 파일은 lib폴더안의 파일에서 이루어 진다.

pubspec.yaml은 이미지를 추가하거나 API 또는 모듈등을 추가할 때 사용한다.

main.dart파일에 들어가보면 다음과 같은 코드를 볼 수 있다.

runApp을 통해 최종적인 위젯이 렌더링 된다. class를 통해 위젯을 정의할 수 있고 함수를 통해 위젯을 반환하는것도 가능하다.

  • MaterialApp: 구글이 제공하는 Material Design 3를 사용할 수 있도록 해주는 클래스다.
  • Scaffold: Scaffold는 Flutter 앱에서 Material Design의 기본적인 시각적 구조를 구현하는 위젯이다. Scaffold는 앱의 주요 구성 요소를 자동으로 배치하여 일관된 레이아웃과 디자인을 제공한다.
  • Center: 자식 요소를 가운데로 배치해준다.
  • Text: 텍스트를 화면에 보여준다.

위 코드를 실행하면(디버깅 모드로 실행하면 코드를 바꾸고 저장하면 변경사항을 즉시 반영해준다.)

다음과 같은 화면을 볼 수 있다.

Material Design 3와 Scaffold를 통해 내장되어있는 여러 버튼이나 텍스트 디코레이션 App Bar 등을 이용할 수 있다.

다양한 레이아웃은 https://docs.flutter.dev/development/ui/widgets/layout 이 공식문서 페이지에서 확인할 수 있다.

Statefull, Stateless

두 위젯을 이해하기 위해 계산기를 구현해본다.

  • AppBar는 상단 앱 바를 쉽게 구현하도록 해준다. title을 통해 앱 바의 중앙 타이틀을 설정해줄 수 있다.
  • MainAxisAlignment.center 는 Row 또는 Column에서 볼 수 있는데 주 축을 기준으로 어떻게 배열할것인지를 정하게 해준다. 여기서는 Column의 주 축인 세로축을 기준으로 중앙 정렬했다.
  • 레이아웃 위젯은 자식요소를 하나만 가지는, 프로퍼티 child를 가지는 위젯과 자식요소를 여러개 가지는 즉, children을 프로퍼티로 가지는 크게 두 종류의 위젯이 있다. Row와 Column은 children을 통해 자식을 배열로 입력받아 자식들을 가로 또는 세로로 정렬시킨다.
  • 템플릿 문자열을 통해 변수를 텍스트로 렌더링 할 수 있도록 했다.
  • SizedBox는 위아래, 좌우 간격을 추가하기 위해 사용되는 위젯이다.
  • ElevatedButton은 버튼 위젯이다. onPressed 와 child를 반드시 정의해줘야 하며, onPressed는 버튼 클릭시 실행한 함수를 정의해주고 child에는 내부에 표현될 아이콘이나, 텍스트 등의 장식을 추가해주면 된다.


하지만 위 예제에 onPressed 함수에 카운트를 더해주는 작업을 하더라도 아무일도 일어나지 않는다. 이유는 이 앱이 실행되면서 MainApp 클래스가 딱 한번 빌드되는데 onPressed 이벤트 리스너의 핸들러를 통해 변수가 바뀌긴 하지만 변수가 변경되는걸 화면으로 확인하려면 변수가 바뀔 때 마다 다시 빌드를 하도록 해주어야 한다.

이러한 문제를 해결 할 수 있도록 해주는 것이 stateful 위젯의 setState함수다. 이 함수를 이용해 변수를 변경하면 빌드가 재 실행되면서 변수의 변경을 화면을통해 확인할 수 있다.


stateless 위젯 클래스와 똑같은 statefull 위젯이다. 달라진 점은 count++을 진행하는 void함수를 정의했고, 그 함수를 onPressed 이벤트 리스너에 전달해서 클릭시마다 해당 함수가 호출되고 setState를 통해 호출된 count++을 값이 변경될 때 마다 위젯을 다시 빌드한다는 것이다.

stateless 위젯을 stateful 위젯으로 다음과 같이 간단하게 변경할 수 있다.

statelessWidget 위에 커서를 두면 전구표시가 나오는데 전구를 클릭하면 statefulwidget으로 변경해주는 메뉴가 나온다.

다음과 같이 잘 작동한다.

Http 통신

https://docs.flutter.dev/development/data-and-backend/networking 해당 문서를 참조해 작성했다.

우선 안드로이드에서 사용하기 위해서는 AndroidManifest.xml파일에 권한을 추가해줘야 한다.
플러터 프로젝트 루트 디렉토리/android/app/src/main/AndroidManifest.xml 의 파일을 변경해야 한다.

<uses-permission android:name="android.permission.INTERNET" />를 permission에 추가해준다.

위와 같이 추가해준다.

다음으로 http패키지를 추가해준다.

pubspec.yaml파일에 dependencies를 추가해준 뒤 우측 상단에 Get Package를 눌러준다.

또는 다음 터미널 커맨드로 추가해줄 수 있다.

flutter pub add http

이후 http를 import 해준다.

네트워크 요청을 한다.

jsonplaceholder라는 서버에 posts/1 을 Get하는 요청을 보냈다.

응답과 일치하는 커스텀 다트 클래스를 만든다.

http.response를 Post클래스로 변경한다.

Post클래스로 변경된 요청을 변수에 담는다.

이후 이걸 화면에 출력해본다.

화면

이렇게 잘 작동하는걸 볼 수 있다.

전체 코드

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

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

class MainApp extends StatefulWidget {
  const MainApp({super.key});

  
  State<MainApp> createState() => _MainAppState();
}

class _MainAppState extends State<MainApp> {
  late Future<Post> futurePost; // late는 변수를 선언할 때 초기화하지 않아도 된다는 것을 의미한다.
  
  void initState() {
    // TODO: implement initState
    super.initState();
    futurePost = fetchPost(); // initState()함수에 있는 실행문들은 딱 한번만 실행되기 때문에 요청을 보내는 모드를
    // 여기서 초기화 해준다.
  }

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('HTTP 통신 예제'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              FutureBuilder(future: futurePost, builder: (context, snapshot,) { /* snpashot은 FutureBuilder의 future 변수에 있는 futurePost가 반환하는 값을 가지고 있다. */
                if (snapshot.hasData) {
                  return Text(snapshot.data!.title);
                } else if (snapshot.hasError) {
                  return Text('${snapshot.error}');
                }

                return const CircularProgressIndicator();
              },)
            ],
          ),
        ),
      ),
    );
  }

  Future<Post> fetchPost() async { // 응답을 Json으로 받아 Post로 반환하는 함수
    final response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/posts/1'));

    if (response.statusCode == 200) { // 서버가 요청을 정상적으로 처리했을 때
      return Post.fromJson(jsonDecode(response.body)); // jsonDecode를 통해 json을 Map으로 변환 후
      // Post로 변경해 반환
    } else {
      throw Exception('Post를 불러오는데 실패했습니다.');
    }
  }
}

class Post { // Post 클래스
  final int userId;
  final int id;
  final String title;
  final String body;

  const Post({ // final을 통해 선언된 변수는 required를 통해 반드시 이 변수가 필요하다는 것을 명시해줘야 한다.
    required this.userId,
    required this.id,
    required this.title,
    required this.body
  });

  factory Post.fromJson(Map<String, dynamic> json) { // factory는 new 연산자를 사용하지 않곡 객체를 생성할 수 있게
  // 해준다.
    return Post(
      userId: json['userId'],
      id: json['id'],
      title: json['title'],
      body: json['body'],
    );
  }
}

이런 방식으로 REST API를 구현할 수 있다.

Google Map API 사용

Google Map API를 사용하기 위해서 일단 API키를 발급받는다.
https://cloud.google.com/maps-platform/

https://developers.google.com/maps/apis-by-platform?hl=ko
https://developers.google.com/maps/documentation?hl=ko
위 두 사이트에 자세한 사용방법을 알 수 있다.

안드로이드

android/app/build.gradleminSdkVersion을 20으로 설정한다.

android/app/src/main/AndroidManifest.xml에 API 키를 추가해준다.

pubspec.yaml파일에 디펜던시도 추가해준다.

이제 GoogleMap위젯을 사용할 수 있다.

위와 같은 코드를 작성하면

위와 같은 화면을 출력한다.

https://pub.dev/packages/google_maps_webservice
위 라이브러리를 통해 다양한 google map과 관련된 서비스를 이용할 수 있다.

profile
프론트엔드 개발자

0개의 댓글