구글에서 개발한 크로스 플랫폼 프레임워크.
Dart언어를 기반으로 만들어졌다.
https://docs.flutter.dev/get-started/install/windows
위 링크를 통해 SDK를 다운 받는다.
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이랑 비슷하지만 컴파일 단계에서 인식되기 때문에 반드시 선언과 초기화가 동시에 이루어져야 한다.
다른 언어들의 조건문과 똑같다.
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 이 공식문서 페이지에서 확인할 수 있다.
두 위젯을 이해하기 위해 계산기를 구현해본다.
하지만 위 예제에 onPressed 함수에 카운트를 더해주는 작업을 하더라도 아무일도 일어나지 않는다. 이유는 이 앱이 실행되면서 MainApp 클래스가 딱 한번 빌드되는데 onPressed 이벤트 리스너의 핸들러를 통해 변수가 바뀌긴 하지만 변수가 변경되는걸 화면으로 확인하려면 변수가 바뀔 때 마다 다시 빌드를 하도록 해주어야 한다.
이러한 문제를 해결 할 수 있도록 해주는 것이 stateful 위젯의 setState함수다. 이 함수를 이용해 변수를 변경하면 빌드가 재 실행되면서 변수의 변경을 화면을통해 확인할 수 있다.
stateless 위젯 클래스와 똑같은 statefull 위젯이다. 달라진 점은 count++을 진행하는 void함수를 정의했고, 그 함수를 onPressed 이벤트 리스너에 전달해서 클릭시마다 해당 함수가 호출되고 setState를 통해 호출된 count++을 값이 변경될 때 마다 위젯을 다시 빌드한다는 것이다.
stateless 위젯을 stateful 위젯으로 다음과 같이 간단하게 변경할 수 있다.
statelessWidget 위에 커서를 두면 전구표시가 나오는데 전구를 클릭하면 statefulwidget으로 변경해주는 메뉴가 나온다.
다음과 같이 잘 작동한다.
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를 사용하기 위해서 일단 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.gradle
의 minSdkVersion
을 20으로 설정한다.
android/app/src/main/AndroidManifest.xml
에 API 키를 추가해준다.
pubspec.yaml
파일에 디펜던시도 추가해준다.
이제 GoogleMap
위젯을 사용할 수 있다.
위와 같은 코드를 작성하면
위와 같은 화면을 출력한다.
https://pub.dev/packages/google_maps_webservice
위 라이브러리를 통해 다양한 google map과 관련된 서비스를 이용할 수 있다.