https://pub.dev/packages/http
ํด๋น ์ฌ์ดํธ์์ ์ค์น ๊ฐ๋ฅํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ์ธํ ์ ์๋ค.
flutter pub add (๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ช
)
//http ์ค์น
flutter pub add http
API ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ๋ json ํํ์ ๊ตฌ์กฐ๋ฅผ ์ฑ์์ ์ฌ์ฉํ ๊ฐ์ฒด๋ก ๋ณํํด์ผ ํ๋ค. webtoon app์์ ๊ฐ์ ธ์ฌ ๋ฐ์ดํฐ๋ title, thumb, id ์ด๋ค.
// API ๋ฐ์ดํฐ
[
{
"id": "654774",
"title": "์๋
์ ์ธ๊ณ",
"thumb": "https://image-comic.pstatic.net/webtoon/654774/thumbnail/thumbnail_IMAG21_4048794550434817075.jpg"
},
.
.
.
๐ ํด๋น ๋ฐ์ดํฐ๋ฅผ ๋ณํํ๋ ์ฝ๋
class WebtoonModel {
final String title, thumb, id;
WebtoonModel.fromJson(Map<String, dynamic> json)
: title = json['title'],
thumb = json['thumb'],
id = json['id'];
}
๐ api_service.dart
class ApiService {
static const String baseUrl =
"https://webtoon-crawler.nomadcoders.workers.dev";
static String today = "today";
static Future<List<WebtoonModel>> getTodaysToons() async {
List<WebtoonModel> webtoonInstances = []; // webtoonModel ํ์
์ ์ธ์คํด์ค๋ค์ด ๋ค์ด๊ฐ๊ฒ ๋ ๊ณณ!
final url = Uri.parse('$baseUrl/$today');
// ์ ์ํ url
final response = await http.get(url);
if (response.statusCode == 200) { //์ ์์ ์ผ๋ก ๋ฐ์ดํฐ๊ฐ ๋ฐ์์์ง ๊ฒฝ์ฐ
final List<dynamic> webtoons = jsonDecode(response.body);
for (var webtoon in webtoons) { //for๋ฌธ์ ๋๋ฉด์ ๋ฐ์ดํฐ๋ค์ json ํ์์์ ๊ฐ์ฒด ํํ๋ก ๋ณํํด์ฃผ๊ณ ๋ฐฐ์ด์ add ํด์ค๋ค.
final instance = WebtoonModel.fromJson(webtoon);
webtoonInstances.add(instance);
}
return webtoonInstances; //์นํฐ ์ธ์คํด์ค๋ค(์ฐ๋ฆฌ๊ฐ ๋ฐ์์จ ๋ฐ์ดํฐ)๋ฅผ ์ต์ข
๋ฐํ
}
throw Error();
}
๐ main.dart
final Future<List<WebtoonModel>> webtoons = ApiService.getTodaysToons();
//webtoons : ์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํ ์นํฐ ์ธ์คํด์ค๋ค (ํ์
์ webtoonModel)
์์์ ๋ฐ์์จ api ๋ฐ์ดํฐ(webtoons)๋ฅผ ์ด์ ํ๋ฉด์ ๋ณด์ฌ์ค์ผ ํ๋ค. ์ด๋ futureBuilder๋ฅผ ์ฌ์ฉํ ์ ์๋ค. Future์ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ฐ์ดํฐ๊ฐ ๋ค ๋ฐ์์์ง๊ธฐ ์ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ค๋ ๊ฒ์ ๋ง์์ค๋ค. FutureBuilder๊ฐ ์๋ค๋ฉด ๋ฐ์ดํฐ๊ฐ ๋ค ๋ฐ์์ง๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฐ ํ ํ๋ฉด์ ๊ทธ๋ฆฌ๊ฑฐ๋ ๋ฐ์ดํฐ์ ๋ณํ์ setState()๋ฅผ ํตํด ๋ฐ๊ฟ์ผ ์ค์ผํ๋ค. FutureBuilder๋ ๋๋ถ๋ถ ์จ๋ฒ์์ ์ด๋ฏธ์ง ๊ฐ์ ธ์ค๊ธฐ, ํ์ฌ ๋ฐฐํฐ๋ฆฌ ํ์, ํ์ผ ๊ฐ์ ธ์ค๊ธฐ, http ์์ฒญ ๋ฑ ์ผํ์ฑ ์๋ต์ ์ฌ์ฉํ๋ค.
FutureBuilder(
future: webtoons,
builder: (context, snapshot) {
if (snapshot.hasData) { //๋ฐ์ดํฐ๊ฐ ์์ ๊ฒฝ์ฐ
return Column(
children: [
const SizedBox(
height: 50,
),
Expanded(
child: makeList(snapshot),
//๋ฐ์ดํฐ๋ฅผ ๋ณด์ฌ์ฃผ๋ ํจ์ ์คํ. makeList๋ ๋ฐ๋ก ์์ฑํ ์ฝ๋(ListView์์ ์ค๋ช
ํ ์์ )
),
],
);
}
return const Center( //future๊ฐ ๋ถ๋ฌ์์ง๊ธฐ ์ data๊ฐ ์์ผ๋ฏ๋ก ๋ก๋ฉ์ก์
์ด ํ๋ฉด์ display๋๋ค.
child: CircularProgressIndicator(),
);
},
),
ListView.builder์ ๋ช ๊ฐ์ ํญ๋ชฉ์ ๋ง๋ค ๊ฒ์ด๊ณ ๋ช ๋ฒ์งธ ํญ๋ชฉ์๋ ์ด๋ค View๋ฅผ ๊ทธ๋ ค์ฃผ์๋ผ๋ ๊ฒ์ ์๋ ค์ฃผ์ด์ผ ํ๋ค. itemCount๊ฐ ์ด ๋ช ๊ฐ์ ํด๋นํ๊ณ , itemBuilder๊ฐ ์ด๋ค View๋ฅผ ๊ทธ๋ ค์ฃผ์ ๋ผ๋ ๊ฒ์ ํด๋นํ๋ค.
ListView makeList(AsyncSnapshot<List<WebtoonModel>> snapshot) {
return ListView.separated(
scrollDirection: Axis.horizontal,
//scrollDirection : Axis.horizontal ์ธ ๊ฒฝ์ฐ ๊ฐ๋ก๋ฐฉํฅ์ผ๋ก ํญ๋ชฉ์ด ๋์ด๋๋ฉฐ, ๊ฐ๋ก๋ฐฉํฅ์ผ๋ก ์คํฌ๋กค์ด ๋จ.
itemCount: snapshot.data!.length,
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
itemBuilder: (context, index) {
var webtoon = snapshot.data![index];
return Webtoon(
title: webtoon.title, thumb: webtoon.thumb, id: webtoon.id);
},
separatorBuilder: (context, index) => const SizedBox(
width: 20,
),
);
Hero๋ฅผ ์ด์ฉํด์ ์ ๋๋ฉ์ด์ ์ ์ถ๊ฐํด์ค ์ ์๋ค. tag์ ๊ฐ์ id๋ฅผ ์ ๋ ฅํ๋ฉด ๊ฐ์ ๊ฐ์ฒด๋ก ํ๋จํด ์ด๋ฏธ์ง๊ฐ ํ์ ๋๋ ๊ฒ ๊ฐ์ ์ ๋๋ฉ์ด์ ํจ๊ณผ๊ฐ display ๋๋ค.
//detail_screen.dart
Hero(
tag: widget.id,
child: Container(
width: 250,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
blurRadius: 15,
offset: const Offset(10, 10),
color: Colors.black.withOpacity(0.3),
)
]),
child: Image.network(
widget.thumb,
headers: const {
'Referer': 'https//comic.naver.com',
},
),
),
),
//webtoon_widget.dart
Hero(
tag: id,
child: Container(
width: 250,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
blurRadius: 15,
offset: const Offset(10, 10),
color: Colors.black.withOpacity(0.3),
)
]),
child: Image.network(
thumb,
headers: const {
'Referer': 'https//comic.naver.com',
},
),
),
),
flutter pub add url_launcher
ios์์ ํด๋น ๊ธฐ๋ฅ์ ์ฌ์ฉํ๊ธฐ ์ํด ios/Runner/Info.plist
ํ์ผ์์ ํด๋น ๋ถ๋ถ์ ์ถ๊ฐํ๋ค.
<array>
<string>https</string>
</array>
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
void main() => runApp(
const MaterialApp(
home: Material(
child: Center(
child: ElevatedButton(
onPressed: onButtonTap,
child: Text('Show Flutter homepage'),
),
),
),
),
);
//์์ 1
onButtonTap() async {
final url=Uri.parse('์ด๋ํ ์ฃผ์');
await launchUrl(url);
}
//์์ 2
onButtonTap() async {
launchUrlString('์ด๋ํ ์ฃผ์');
}
}
Webtoon App์์ ํด๋น ์นํฐ์ ํ์ฐจ๋ก ์ด๋์ํค๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํด์ฃผ์๋ค.
onButtonTap() async {
await launchUrlString(
"https://comic.naver.com/webtoon/detail?titleId=$webtoonId&no=${episode.id}");
//webtoonId , episodeId์ ํด๋นํ๋ ํ์ฐจ๋ก ์ด๋
}
์ฐธ๊ณ ๊ฐ์
https://nomadcoders.co/flutter-for-beginners/lobby