Dev study and notes

플러터 Flutter로 웹툰 앱 만들기 #6 WEBTOON toonflix APP 본문

Building & Learning/Flutter로 웹툰앱 만들기(2023)

플러터 Flutter로 웹툰 앱 만들기 #6 WEBTOON toonflix APP

devlunch4 2025. 1. 28. 07:20
반응형

이번 강좌에서는 강좌명 그대로 웹툰 앱을 만듭니다.

이전의 강좌는 기본적인 플러터 사용을 위한 연습용 앱(디자인 연습, 타이머 앱)을 만들었다면,

플러터를 통해 웹툰 앱을 만드는 것입니다.

#6 WEBTOON APP

#6.0 Introduction (05:09)

  • 이제까지 배운 것을 활용합니다.
  • 네이버 웹툰 사이트의 api 사용합니다.
  • 데이터 불러오기, 인터넷에서 패키지를 다운 받아 사용하기, 스마트폰 api 사용하는 법,

폰에 데이터를 저장하는 법을 알게 될 것입니다.

  • 니꼬가 만든 비공식 네이버 웹툰 api를 사용합니다

https://webtoon-crawler.nomadcoders.workers.dev/

 

네이버 웹툰 Unofficial API

 

webtoon-crawler.nomadcoders.workers.dev

 

오늘자정보,

웹툰 정보,

최신 에피소드 정보

를 api를 통해 받아볼 수 있습니다.

웹 화면과 이동화면 두 개를 구현할 예정입니다.

* main.dart source

import 'package:flutter/material.dart';
import 'package:toonflix/screens/home_screen.dart';

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

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomeScreen(),
    );
  }
}

*lib/screens/home_screen.dart

import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        elevation: 2,
        foregroundColor: Colors.green,
        backgroundColor: Colors.white,
        title: const Text(
          "Today's Toon's (오늘의 웹툰)",
          style: TextStyle(
            fontSize: 26,
            // fontWeight: FontWeight.w600,
          ),
        ),
      ),
    );
  }
}

#6.1 AppBar (05:58)

#6.2 Data Fetching (11:44)

services 폴더 생성 후 소스코드 작성 및 라이브러리 확인 추가

라이브러리 확인 후

라이브러리 패키지 설치합니다.

pubspec.yaml에 드래그 소스 추가

api_service.dart 생성 및 소스 추가

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

class ApiService {
  final String baseUrl = "https://webtoon-crawler.nomadcoders.workers.dev";
  final String today = "today";

  void getTodaysToons() async {
    final url = Uri.parse('$baseUrl/$today');
    final response = await http.get(url);
    //async programming - wait something do happened. side effect
    if (response.statusCode == 200) {
      print(response.body);
      return;
    }
    throw Error();
  }
}

main.dart 소스 수정 추가

import 'package:flutter/material.dart';
import 'package:toonflix/screens/home_screen.dart';
import 'package:toonflix/services/api_service.dart';

void main() {
  ApiService().getTodaysToons();
  runApp(const App());
}

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomeScreen(),
    );
  }
}

디버그 실행 시 콘솔 창에 json 타입으로 출력 되는지 확인되면 성공!

#6.3 fromJson (09:59)

이어서 새로운 폴더 models 생성 및 webtoon_model.dart 파일을 생성합니다.

강의에 따라 소스 작성 후 실행하면 리턴 목록을 설정 및 확인 가능합니다

이후 리스트 타입으로 설정하여 출력 및 리턴 설정합니다.

 

#6.4 Recap (06:09)

복습 및 일부 소스 수정

#6.5 waitForWebToons (05:48)

StatelessWidget 을 StatefulWidget로 변경하며 소스 수정합니다.

data를 fatch 하여 처리하도록 수정합니다.

#6.6 FutureBuilder (07:05)

StatelessWidget 사용 후 FutureBuilder 사용법을 안내합니다.

#6.7 ListView (11:59)

ListView 사용방법 안내

메모리 최적화를 위해 스크롤 시 로딩 설정 완료!

플러터 최적화를 사용한다.

#6.8 Webtoon Card (13:55)

home_screen.dart 소스

import 'package:flutter/material.dart';
import 'package:toonflix/models/webtoon_model.dart';
import 'package:toonflix/services/api_service.dart';

class HomeScreen extends StatelessWidget {
  HomeScreen({super.key});

  final Future<List<WebtoonModel>> webtoons = ApiService.getTodaysToons();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        elevation: 2,
        foregroundColor: Colors.green,
        backgroundColor: Colors.white,
        title: const Text(
          "Today's Toon's (오늘의 웹툰)",
          style: TextStyle(
            fontSize: 26,
            // fontWeight: FontWeight.w600,
          ),
        ),
      ),
      body: FutureBuilder(
        future: webtoons,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return Column(
              children: [
                const SizedBox(
                  height: 50,
                ),

                Expanded(child: makeList(snapshot))
                ////makeList(snapshot)
              ],
            );
          }
          return const Center(
            child: CircularProgressIndicator(),
          );
        },
      ),
    );
  }

  ListView makeList(AsyncSnapshot<List<WebtoonModel>> snapshot) {
    return ListView.separated(
      scrollDirection: Axis.horizontal,
      itemCount: snapshot.data!.length,
      padding: const EdgeInsets.symmetric(
        vertical: 10,
        horizontal: 20,
      ),
      itemBuilder: (context, index) {
        var webtoon = snapshot.data![index];
        return Column(
          children: [
            Container(
              width: 250,
              clipBehavior: Clip.hardEdge,
              decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(15),
                  boxShadow: [
                    BoxShadow(
                      blurRadius: 7,
                      offset: const Offset(10, 10),
                      color: Colors.black.withOpacity(0.5),
                    )
                  ]),
              child: Image.network(webtoon.thumb),
            ),
            const SizedBox(
              height: 10,
            ),
            Text(
              webtoon.title,
              style: const TextStyle(
                fontSize: 22,
              ),
            ),
          ],
        );
      },
      separatorBuilder: (context, index) => const SizedBox(width: 40),
    );
  }
}

#6.9 Detail Screen (13:37)

웹툰 표지를 클릭/탭 했을 때 새로운 화면 전환을 구현합니다.

#6.10 Hero (04:58) 

#6.11 Recap (05:30)

#6.12 ApiService (10:15)

새로운 모델을 작성하고 해당 모델을 받아 리스트로 리턴하는 api 서비스를 생성합니다.

#6.13 Futures (07:48)

API 소스 활용을 위해 스크린 부분에 소스 추가합니다.

#6.14 Detail Info (06:10)

화면에 상세 정보를 볼 수 있도록 추가합니다.

 

#6.15 Episodes (15:45)

에피소드 부분의 리스트를 화면에 구현합니다.

#6.16 Url Launcher (12:31)

URL Launcher를 사용하여 해당 링크로 이동하게 설정합니다.

#6.17 Favorites (17:10)

하트 아이콘을 생성합니다.

하트를 눌렀을 때 카운트가 추가 되도록 shared preferences를 설치합니다.

터미널 콘솔 창에 "flutter pub add shared_preferences"를 입력하여 설치합니다.

https://pub.dev/packages/shared_preferences

이어서 선언부 설정을 합니다.

그리고 난 뒤 하트 클릭 시 즐겨 찾는 웹툰의 정보를 사용 중인 기기에 저장을 합니다.

이후에도 불러올 수 있도록 합니다.

시연을 하게 되고 이번 강의가 마무리됩니다.

#6.18 Thank You (02:21)

강좌 끝!

시연 영상을 녹화해 보았습니다.

https://youtu.be/NcS8d-UoAXM

 

 

끝!

반응형
Comments