flutter에서 페이지 간 이동 시 URL기반의 API를 이용해서 쉽게 이동할 수 있도록 도와주는 패키지이다.
화면이 출력되는 부분!
(주석으로 설명이 되어 있음)
import 'package:flutter/material.dart';
import 'package:fultter_basic_1/first_page.dart';
import 'package:fultter_basic_1/second_page.dart';
import 'package:fultter_basic_1/third_page.dart';
//메인함수
void main(){
//플러터 프레임워크에 실행요청
runApp(MyApp());
}
//위젯은 화면을 구성하는 요소
class MyApp extends StatelessWidget {
//같은 타입의 위젯이 여러개 있을 경우
//context가 구분할 수 있게 해줌 -> key
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
home:FirstPage(),
//SecondPage(),
//ThirdPage(),
//각 페이지 마다 다름.
);
}
}
first_page.dart를 만들어 main.dart에 build안에 home에서 출력해본다.(주석으로 설명)
// frist_page.dart
import 'package:flutter/material.dart';
class FirstPage extends StatelessWidget {
const FirstPage({Key? key}) : super(key: key);
Widget build(BuildContext context) {
// 통신을 받습니다.
// 통신 데이터는 -> Json String
// 통신에서 받아온 데이터를 파싱했다고 가정
// 파싱 -> 데이터를 다른 형식으로 변경하는 것
List<String> strList = ["첫번째", "두번째"];
// 해당 데이터를 위젯으로 바꿔서 칠드런에 넣고 싶다
// 방법 1. 직접 리스트를 만든다.
// List<Widget> widgetList = [
// Text("첫번째"),
// Text("두번째"),
// ];
// 요소의 타입을 String에서 Widget으로 바꿀 함수
final change = (String str) {
return Text(str);
};
// 방법 2. 함수를 각각 요소에 적용한다.
// List<Widget> widgetList =[
// change("첫번째"),
// change("두번째"),
// ];
// 방법 3.
// list메소드 map은 리스트의 요소를 다른 타입으로 변경할 수 있다
// map이 요소 각각을 change함수를 사용해서 Widget으로 변경
// 리스트로 다시 만들어줌
List<Widget> widgetList = strList.map(change).toList();
return Scaffold(
body: SafeArea(
child: Column(
// children은 위젯 리스트를 받는다.
children: widgetList,
),
),
);
}
}
실행하면 아래와 같이 출력됨.
second_page.dart를 만들어 main.dart에 build안에 home에서 출력해본다.(주석으로 설명)
import 'package:flutter/material.dart';
//받아온 데이터를 필터링해서 변겅
//1 필터링(where) / 2 변경(map)
class SecondPage extends StatelessWidget {
const SecondPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
//받아온 데이터
List<String> strList = ["apple", "google", "naver"];
//a라는 글자가 들어간 str만 필터링 하고 싶음
//Text위젯 리스트로 만들고 싶음
//String을 받아서 a가 들어있는지 확인해서
//있으면 true / 없으면 false를 리턴하는 함수
final filter = (String str){
return str.contains("a");
};
//Stringㅇ르 Widget으로 변경하는 함수
//같은 Widget을 리스트로 사용해서 출력할 경우
//key를 넣어 줘야 한다 -> 같은 애들끼리 구분하기 위해서
final change = (String str) {
return Text(str, key: UniqueKey(),);
};
List<Widget> widgetList = strList.where(filter).map(change).toList();
return Scaffold(
body: SafeArea(
child: Column(
children: widgetList,
),
),
);
}
}
실행하면 'a'가 포함되어 있는 단어들이 출력됨.
Second_page.dart를 만들어 main.dart에 build안에 home에서 출력해본다.(주석으로 설명)
import 'package:flutter/material.dart';
//객체 리스트를 받아서 화면 구성
class ThirdPage extends StatelessWidget {
const ThirdPage({Key? key}) : super(key: key);
Widget build(BuildContext context) {
//파싱된 데이터
List<Post> postList = [
Post(userId: 0, id: 0, title: "제목1", body: "내용1"),
Post(userId: 0, id: 0, title: "제목2", body: "내용2"),
];
//map에서 이용할 요소를 바꾸는 함수
final change = (Post post){
return Row(
children: [
Text("유저번호 : ${post.userId} | "),
Text("글번호 : ${post.id} | "),
Text("제목 : ${post.title} | "),
Text("내용 : ${post.body}"),
],
);
};
return Scaffold(
body: SafeArea(
child: Column(
children: postList.map(change).toList(),
),
),
);
}
}
class Post {
int userId;
int id;
String title;
String body;
// Post(this.userId, this.id, this.title, this.body);
Post({required this.userId, required this.id, required this.title, required this.body});
}
void main(){
Post post1 = new Post(
userId: 0,
id: 0,
title: "제목",
body: "내용"
);
}
실행하면 파싱한 데이터들이 저장된 change가 출력됨.
key-value가 한 쌍으로 여러 쌍이 배열로 이루어진다.
Map<String, dynamic> map = {"a":1,"abc":"aaa"};
기본형은 위와 같이 선언되며 좌측에는 key값, 우측에는 value값이 된다.
즉, key값을 호출해서 value를 받아올 수 있다.
자료구조
Map (key:value 형식의 배열)
List가 가지고 있는 메소드 map (기존 데이터를 다른 타입으로 변경하는 함수)
둘은 다름
map함수가 그래도 이해안되면 아래 코드 참고
class Company {
String name;
Company({required this.name});
}
void main(List<String> args) {
List arr = ["apple", "naver", "google"];
// 요청사항이 들어옴
// Company 타입의 배열로 만들어주세요
// 1번 방식 - 수작업 (요소가 많을 경우 너무 오래걸림)
List<Company> newArr1 = [
Company(name: "apple"),
Company(name: "naver"),
Company(name: "google"),
];
// // 2번 방식 - 새 리스트 만들고 반복문으로 넣어주기
List<Company> newArr2 = List.empty(growable: true);
for (var i = 0; i < arr.length; i++) {
newArr2.add(Company(name: arr[i]));
}
// 3번 방식 - map 사용
// map은 매개변수로 받은 함수 (item) => Company(name: item) 를 이용해서
// 각 요소들을 String -> Company 타입으로 변경
List<Company> newArr3 = arr.map((item) => Company(name: item)).toList();
}
jsonplaceholder의 통신웹페이지처럼 userId와 id, title, body를 flutter로 구현해 본다.
flutter_http_1의 이름으로 새로운 flutter_project를 만든다.
(해당설정은 그림과 같이)
test폴더아래의 생성되는 파일은 삭제해 주고, pubspec.yaml파일로 들어가 sdk: flutter가 적혀있는 아래에 줄을 맞추어 해당 코드를 적어준다.
마지막 Pub get을 꼭 해준다.
http:
flutter_hooks:
provider:
go_router:
lib폴더 아래에 list_page.dart와 detail_page.dart 파일을 생성해 주고, main.dart의 있는 내용은 삭제해준다.
Stateless로 만들어 준다.
(주석으로 설명)
import 'package:flutter/material.dart';
import 'package:flutter_http_1/list_page.dart';
void main(){
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
home: ListPage(),
//home:은 불러와서 실행할 class명을 적으면 됨.
);
}
}
게시판처럼 만들기 위해 작성해 준다.
//post_dto.dart
//테이블 용
class PostDTOTable {
int userId; //유저 번호
int id; //글번호
String title; //제목
//{}로 감싸면 required가 적혀짐.
PostDTOTable({required this.userId, required this.id, required this.title});
}
//상세 페이지 용
class PostDTODetail {
int userId;
int id;
String title;
String body;
PostDTODetail.name(
{required this.userId,
required this.id,
required this.title,
required this.body});
}
alt + insert를 눌리면 생성자를 자동 만들어준다.
설명은 주석으로 되어 있다.
//list_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_http_1/post_dto.dart';
import 'package:http/http.dart' as http; //useEffect사용하기전에 import함.
//as -> 패키지를 http이름으로 사용하겠다는 말
class ListPage extends HookWidget {//HookWidget으로 바꿔줌
const ListPage({Key? key}) : super(key: key);
Widget build(BuildContext context) {
//더미데이터
//PostDTOTable postDTOTable = PostDTOTable(userId: 0, id: 0, title: "테스트 제목");
//실제 데이터
//통신은 실패할 수 있다 = nullable
final listState = useState<List<PostDTOTable>?>(null);
//?를 넣어줘야 null이 될 수 있음(java랑 다름)
final jsonState = useState<String?>(null);
//useEffect(작동함수, 관찰할 상태 리스트);
//빌드가 완료되면 작동한다
//관찰하는 상태가 변경되면 작동한다
//관찰하는 상태가 없으면 빌드 시 1번 작동한다
useEffect((){
String url = "https://jsonplaceholder.typicode.com/posts";
http.get(Uri.parse(url)).then((response) {
jsonState.value = response.body;
});
},[]);
return Scaffold(
body: SafeArea(
child: ListView(
children: [
Text(jsonState.value ?? "값이 없습니다"),//null이면 값이 없다고
],
),
),
);
}
}
class ListItem extends StatelessWidget {
PostDTOTable postDTOTable;
ListItem({Key? key,required this.postDTOTable}) : super(key: key);
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(border: Border.all(width: 2, color: Colors.black)),
child: Column(
children: [
Text("유저 번호 ; ${postDTOTable.userId}"),
Divider(),
Text("글 번호 ; ${postDTOTable.id}"),
Divider(),
Text("글 제목 ; ${postDTOTable.title}"),
Divider(),
],
),
);
}
}
웹으로 실행하면 아래의 화면과 같이 출력된다.
통신(코드해석)
->문자열이 날아옴 ->문자열을 파싱 (내가 필요한 타입으로 변경) ->jsonDecode ->dynamic (dynamic 모든 타입을 받을 수 있음) (dynamic 모든 타입으로 변할 수 있음) (개발자 알아서 파싱해서 쓰라고) ->리스트로 캐스팅(형변환) ->DTO객체 생성 json데이터의 값을 넣어줌 ->DTO를 편하게 쓰기 위해 factory 사용
json과 관련된 것은 다 주석처리했다.
(설명은 역시나 주석으로 함)
//list_page.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_http_1/post_dto.dart';
import 'package:http/http.dart' as http; //useEffect사용하기전에 import함.
//as -> 패키지를 http이름으로 사용하겠다는 말
class ListPage extends HookWidget {
const ListPage({Key? key}) : super(key: key);
Widget build(BuildContext context) {
//더미데이터
//PostDTOTable postDTOTable = PostDTOTable(userId: 0, id: 0, title: "테스트 제목");
//실제 데이터
//통신은 실패할 수 있다 = nullable
final listState = useState<List<PostDTOTable>?>(null);
//?를 넣어줘야 null이 될 수 있음(java랑 다름)
// final jsonState = useState<String?>(null);
//useEffect(작동함수, 관찰할 상태 리스트);
//빌드가 완료되면 작동한다
//관찰하는 상태가 변경되면 작동한다
//관찰하는 상태가 없으면 빌드 시 1번 작동한다
useEffect((){
String url = "https://jsonplaceholder.typicode.com/posts";
http.get(Uri.parse(url)).then((response) {
//추가(
//정사적으로 받아왔는지 체크
//200은 정상 응답
if(response.statusCode == 200) {
//string을 json형식으로 파싱
dynamic decodedBody = jsonDecode(
response.body); //아무거나 받을 때 dynamic으로 함.
//json을 Map List로 캐스팅
List jsonList = decodedBody as List;
//list가 됐긴 때문에 아래에 list map을 할 수 있음
//List를 map 함수로 풀어서 요소를 PostDTOTable로 변경
//state에 입력
listState.value = jsonList.map((data) {
return PostDTOTable(
userId: data["userId"], id: data["id"], title: data["title"]);
}).toList();
}
//jsonState.value = response.body;
});
},[]);
return Scaffold(
body: SafeArea(
child: ListView(
children: listState.value?.map((e) => ListItem(postDTOTable: e)).toList() ?? [],
// Text(jsonState.value ?? "값이 없습니다"),//null이면 값이 없다고
),
),
);
}
}
class ListItem extends StatelessWidget {
PostDTOTable postDTOTable;
ListItem({Key? key,required this.postDTOTable}) : super(key: key);
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(border: Border.all(width: 2, color: Colors.black)),
child: Column(
children: [
Text("유저 번호 ; ${postDTOTable.userId}"),
Divider(),
Text("글 번호 ; ${postDTOTable.id}"),
Divider(),
Text("글 제목 ; ${postDTOTable.title}"),
Divider(),
],
),
);
}
}
실행을 하게 되면 아래와 같이 출력된다.
위와 다른 점이라면 여기는 게시판 형식으로 출력되는 것이다.
다음 jsonplaceholder에서 id,name,email만 가져와서 만들어 출력해본다.
flutter_http_myself로 project를 만든다.
(나머지 파일들의 설정과 이름은 위와 똑같이 만든다.)
main.dart
import 'package:flutter/material.dart';
import 'package:flutter_http_myself/list_page.dart';
void main(){
runApp(MyApp());
//실행할 수 있게 runApp을 해줌.
}
//StatelessWidget으로 한다
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return MaterialApp(
home: ListPage(),
);
}
}
post_dto.dart
class PostDTOTable{
//id, name, email의 타입을 지정해 생성자 만들어 줌
int id;
String name;
String email;
PostDTOTable({required this.id, required this.name, required this.email});
}
list_page.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_http_myself/post_dto.dart';
import 'package:http/http.dart' as http;
class ListPage extends HookWidget {//HookWidget을 바꿈
const ListPage({Key? key}) : super(key: key);
Widget build(BuildContext context) {
final listState = useState<List<PostDTOTable>?>(null);
//실패하면 null이 나오게
useEffect((){
String url = "https://jsonplaceholder.typicode.com/users";
//id,name,email 예시의 json링크를 넣음
http.get(Uri.parse(url)).then((response){
if(response.statusCode == 200){//200은 정상응답
dynamic decodeBody = jsonDecode(response.body);
List jsonList = decodeBody as List;
listState.value = jsonList.map((data){
return PostDTOTable(id: data["id"], name: data["name"], email: data["email"]);
}).toList();
}
});
},[]);
return Scaffold(
body: SafeArea(
child: ListView(
children: listState.value?.map((e) => ListItem(postDTOTable: e)).toList() ?? [],
//children 안에 적어줘야 나옴.
),
),
);
}
}
class ListItem extends StatelessWidget {
PostDTOTable postDTOTable;
ListItem({Key? key,required this.postDTOTable}) : super(key: key);
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(border: Border.all(width: 2, color: Colors.black)),
child: Column(
children: [
Text("유저 번호 ; ${postDTOTable.id}"),
Divider(),
Text("유저 이름 ; ${postDTOTable.name}"),
Divider(),
Text("유저 이메일 ; ${postDTOTable.email}"),
Divider(),
],
),
);
}
}
아래의 화면과 같이 출력된다(성공!!!!!!!!)