-
- 아래는 공개된 API의 리스트를 공유하는 Github 문서이다. 아래의 링크에 들어가서, 공개되어있는 API중 하나를 분석하고 직접 기획하여 본인이 기획한 어플을 제작하시오.
- 기획 과제내용을 간단히 2-3줄로 설명하여 제출하시오. 이 때 해결 과정을 함께 포함하여 정리하시오. (어려웠던 내용과 헤맸던 내용이 있다면 반드시 기재할 것)
- 다음의 조건을 반드시 만족할 것.
- 페이지는 두 페이지 이상이어야 하며 네비게이션을 활용하여 페이지 이동이 포함될 것
- 클래스를 작성하여 Serialization이 적용될 수 있도록 할 것
- 적절한 애니메이션 효과를 포함할 것
API를 고르는데 뭐가 뭔지 모르겠고.. 그래도 스포츠앱을 만들어 보고 싶어서 찾아봤는데 키가 있어야하고.. 해리포터 API가 JSON이 쉽게 바로 나와서 해리포터 API를 골랐다.
all characters: 전체 등장인물 https://hp-api.onrender.com/api/characters characters who are Hogwarts students during the book series: 호그와트 학생 https://hp-api.onrender.com/api/characters/students characters who are Hogwarts staff during the book series: 호그와트 직원 https://hp-api.onrender.com/api/characters/staff characters in a certain house, e.g. /gryffindor: 등장인물 기숙사 https://hp-api.onrender.com/api/characters/house/:house all spells: 마법주문 https://hp-api.onrender.com/api/spells
이런 예제도 나와있어서 비슷하게 만들어보고싶다.
아직 이해를 못했나봅니다 제가..
import 'package:harrypoter_app/model/wand.dart'; class Character { String id; String name; List<String>? alternate_names; String species; String gender; String? house; DateTime? dateOfBirth; String? yearOfBirth; bool wizard; String? ancestry; String? eyeColour; String hairColour; Wand wand; String? patronus; bool hogwartsStudent; bool hogwartsStaff; String? actor; List<String>? alternate_actors; bool alive; String? image; Character({ required this.id, required this.name, required this.alternate_names, required this.species, required this.gender, required this.house, required this.dateOfBirth, required this.yearOfBirth, required this.wizard, required this.ancestry, required this.eyeColour, required this.hairColour, required this.wand, required this.patronus, required this.hogwartsStudent, required this.hogwartsStaff, required this.actor, required this.alternate_actors, required this.alive, required this.image, }); factory Character.fromMap(Map<String, dynamic> map) { return Character( id: map['id'], name: map['name'], alternate_names: map['alternate_names'] != null ? List<String>.from(map['alternate_names']) : null, species: map['species'], gender: map['gender'], house: map['house'], dateOfBirth: map['dateOfBirth'], yearOfBirth: map['yearOfBirth'], wizard: map['wizard'], ancestry: map['ancestry'], eyeColour: map['eyeColour'], hairColour: map['hairColour'], wand: Wand.fromMap(map['wand']) , patronus: map['patronus'], hogwartsStudent: map['hogwartsStudent'], hogwartsStaff: map['hogwartsStaff'], actor: map['actor'], alternate_actors: map['alternate_names'] != null ? List<String>.from(map['alternate_actors']) : null, alive: map['alive'], image: map['image']); } }
등장인물 JSON에 있는 타입은 다 넣었고 null일 수도 있는것들을 nullsafety처리
lib/model/wand.dart
class Wand { String? wood; String? core; int? length; Wand({required this.wood, required this.core, required this.length}); factory Wand.fromMap(Map<String, dynamic> map) { return Wand(wood: map['wood'], core: map['core'], length: map['length']); } }
main.dart
import 'package:flutter/material.dart'; import 'package:harrypoter_app/page/mainpage.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( theme: ThemeData.dark(), home: MainPage(), ); } }
lib/page/mainpage.dart
여기부터 테스트하면서 해보려고 일단 대충만들어놓음
import 'package:flutter/material.dart'; import 'package:harrypoter_app/page/spellpage.dart'; import 'package:harrypoter_app/page/staffpage.dart'; import 'package:harrypoter_app/page/studentpage.dart'; class MainPage extends StatefulWidget { const MainPage({super.key}); @override State<MainPage> createState() => _MainPageState(); } class _MainPageState extends State<MainPage> { @override Widget build(BuildContext context) { return Scaffold( body: Container( alignment: Alignment.center, decoration: BoxDecoration( image: DecorationImage( fit: BoxFit.cover, colorFilter: ColorFilter.mode(Colors.black38, BlendMode.darken), image: NetworkImage( 'https://images.christiandaily.co.kr/data/images/full/68175/image.jpg?w=600'))), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ ListTile( onTap: () { Navigator.push(context, MaterialPageRoute(builder: ((context) { return StudentPage(); }))); }, tileColor: Colors.white, title: Text('호그와트 학생'), subtitle: Text('명단보기'), ), ListTile( onTap: () { Navigator.push(context, MaterialPageRoute(builder: ((context) { return StaffPage(); }))); }, tileColor: Colors.white, title: Text('호그와트 직원'), subtitle: Text('명단보기'), ), ListTile( onTap: () { Navigator.push(context, MaterialPageRoute(builder: ((context) { return SpellPage(); }))); }, tileColor: Colors.white, title: Text('호그와트 마법주문'), subtitle: Text('윙가르디움 레비오사~'), ), ], ), ), ), ); } }
MainPage spell.dart
class Spell { String id; String name; String descriprion; Spell({required this.id, required this.name, required this.descriprion}); factory Spell.fromMap(Map<String, dynamic> map) { return Spell( id: map['id'], name: map['name'], descriprion: map['descriprion']); } }
SpellPage.dart
// ignore_for_file: prefer_const_constructors import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:harrypoter_app/model/spell.dart'; class SpellPage extends StatefulWidget { const SpellPage({super.key}); @override State<SpellPage> createState() => _SpellPageState(); } class _SpellPageState extends State<SpellPage> { List<Spell> spell = []; Dio dio = Dio(); var url = 'https://hp-api.onrender.com/api/spells'; readData() async { var res = await dio.get(url); if (res.statusCode == 200) { var magic = List<Map<String, dynamic>>.from(res.data); setState(() => spell = magic.map((e) => Spell.fromMap(e)).toList()); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( centerTitle: true, backgroundColor: Colors.transparent, elevation: 0, title: Text( 'Spell', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30), ), ), body: ListView.builder( itemCount: spell.length, itemBuilder: ((context, index) { return ListTile( title: Text(spell[index].name), subtitle: Text(spell[index].descriprion), ); }))); } }
일단 SpellPage부터 막혔다. ListTile형태로 스크롤하면서 내리려고 했는데..
아무것도 뜨지않음;
StaffPage.dart
// ignore_for_file: prefer_const_constructors import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:harrypoter_app/model/character.dart'; class StaffPage extends StatefulWidget { const StaffPage({super.key}); @override State<StaffPage> createState() => _StaffPageState(); } class _StaffPageState extends State<StaffPage> { List<Character> staffs = []; Dio dio = Dio(); var url = 'https://hp-api.onrender.com/api/characters/staff'; readData() async { var res = await dio.get(url); if (res.statusCode == 200) { var staff = List<Map<String, dynamic>>.from(res.data); setState(() => staffs = staff.map((e) => Character.fromMap(e)).toList()); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( centerTitle: true, title: Text( 'Staff', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30), ), backgroundColor: Colors.transparent, elevation: 0, ), body: Container( alignment: Alignment.center, decoration: BoxDecoration( image: DecorationImage( fit: BoxFit.cover, colorFilter: ColorFilter.mode(Colors.black38, BlendMode.darken), image: NetworkImage( 'https://mblogthumb-phinf.pstatic.net/20110728_125/eponine77_1311816657845yd7Co_JPEG/67900_S45_130538.jpg?type=w2'))), child: PageView.builder( itemCount: staffs.length, itemBuilder: ((context, index) { return Center(child: Image.network(staffs[index].image!)); }))), ); } }
lib/page/studentpage.dart
// ignore_for_file: prefer_const_constructors import 'package:flutter/material.dart'; import 'package:flutter/src/widgets/container.dart'; import 'package:flutter/src/widgets/framework.dart'; class StudentPage extends StatefulWidget { const StudentPage({super.key}); @override State<StudentPage> createState() => _StudentPageState(); } class _StudentPageState extends State<StudentPage> { @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Text('학생페이지'), ), ); } }
dio부분 강의를 다시 들어보겠습니다..
class부분은 맞는지 알고싶습니다.