Group Study (2024-2025)/Flutter

[Flutter] 9주차_스터디_api 활용해보기

dnwls-dev 2024. 12. 2. 02:04

구현 📷

 

 

1. Hero widget

Hero(
                tag: widget.id,
                child: Container(
                  width: 200,
                  clipBehavior: Clip.hardEdge,
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(15),
                      boxShadow: [
                        BoxShadow(
                            blurRadius: 15,
                            offset: const Offset(2, 2),
                            color: Colors.black.withOpacity(0.5)),
                      ]), //clipBehavior -> borderRadius 적용 안 됨
                  child: Image.network(
                    widget.thumb,
                    headers: const {
                      'Referer': 'https://cosmic.naver.com',
                    },
                  ),
                ),
              ),

 

Hero 위젯

  • Hero 위젯은 애니메이션을 통해 화면 전환 시 이미지가 부드럽게 이동하는 효과를 제공한다.
  • tag 속성에 고유 값을 widget.id로 설정하여 Hero 애니메이션의 대상이 되도록 했다.

 


2. ApiService

static Future<WebtoonDetailModel> getToonByID(String id) async {
    final url = Uri.parse("$baseUrl/$id");
    final response = await http.get(url);
    if (response.statusCode == 200) {
      final webtoon = jsonDecode(response.body);
      return WebtoonDetailModel.fromJson(webtoon);
    }
    throw Error();
  }

  static Future<List<WebtoonEpisodeModel>> getLatestEpisodesById(
      String id) async {
    List<WebtoonEpisodeModel> episodesInstances = [];
    final url = Uri.parse("$baseUrl/$id/episodes");
    final response = await http.get(url);
    if (response.statusCode == 200) {
      final episodes = jsonDecode(response.body);
      for (var episode in episodes) {
        episodesInstances.add(WebtoonEpisodeModel.fromJson(episode));
      }
      return episodesInstances;
    }
    throw Error();
  }

getToonByID 메서드

  • 특정 ID를 가진 웹툰의 세부 정보를 비동기로 가져오는 함수이다.
  • 입력받은 id를 통해 baseUrl에 URL을 구성했고, 이를 사용해 HTTP GET 요청을 보내도록 한다.
  • 요청 성공) 응답 상태 코드가 200일 경우, response.body를 JSON 디코딩하여 WebtoonDetailModel로 변환한다.
  • 요청 실패) 요청이 실패하면 예외 처리를 수행

 

getLatestEpisodesById 메서드

  • 특정 ID를 가진 웹툰의 최신 에피소드 목록을 비동기로 가져오는 함수이다.
  • 입력받은 id를 사용해 에피소드 목록 요청 URL을 생성했다.
  • 응답이 성공적이면, JSON 데이터를 디코딩하여 WebtoonEpisodeModel 리스트로 변환했다.
  • 에피소드 데이터를 순회하며 WebtoonEpisodeModel.fromJson 메서드를 통해 객체로 변환 후 리스트에 추가했다.
  • 요청이 실패하면 Error를 던져 예외를 처리했다.

 

 


3. Future

class DetailScreen extends StatefulWidget {
  final String title, thumb, id;

  const DetailScreen({
    super.key,
    required this.title,
    required this.thumb,
    required this.id,
  });

  @override
  State<DetailScreen> createState() => _DetailScreenState();
}

class _DetailScreenState extends State<DetailScreen> {
  late Future<WebtoonDetailModel> webtoon;
  late Future<List<WebtoonEpisodeModel>> episodes;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    webtoon = ApiService.getToonByID(widget.id);
    episodes = ApiService.getLatestEpisodesById(widget.id);
  }

DetailScreen 클래스

  • StatefulWidget을 상속받아 상태를 가진 화면 위젯을 정의했다. 이 클래스는 title, thumb, id라는 세 개의 필드를 필수로 받도록 한다.

_DetailScreenState 클래스

  • DetailScreen의 상태를 정의했다. 두 개의 Future 타입 필드인 webtoon과 episodes를 선언하고, 각각 웹툰 세부 정보와 최근 에피소드 데이터를 비동기로 처리하도록 설정했다.

initState 메서드

  • 상태 초기화 메서드를 오버라이드했다. ApiService.getToonByID(widget.id)와 ApiService.getLatestEpisodesById(widget.id)를 호출하여 비동기 데이터를 초기화한다. super.initState()를 호출하여 부모 클래스의 초기화 로직을 유지하도록 한다.

4. UI

Padding(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 50,
                  ),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        snapshot.data!.about,
                        style: const TextStyle(
                          fontSize: 16,
                        ),
                      ),
                      const SizedBox(
                        height: 15,
                      ),
                      Text(
                        '${snapshot.data!.genre} / ${snapshot.data!.age}',
                        style: const TextStyle(
                          fontSize: 16,
                          fontWeight: FontWeight.w600,
                        ),
                      ),
                    ],
                  ),
                );

padding

  • Text위젯을 padding으로  감싸 수평 방향으로 50px만큼의 공간을 할당한다.  

Column: 자식 위젯들을 세로로 나

  • (웹툰 줄거리 - (장르 / 이용연령)) — 나열 순서
  • crossAxisAlignment를 CrossAxisAlignment.start로 설정하여 가운데 정렬이었던 text를 왼쪽 정렬로 배치했다.

 


참고

 

Flutter 로 웹툰 앱 만들기 – 노마드 코더 Nomad Coders

Flutter for Beginners

nomadcoders.co