28일차 과제 - rlatkddbs99/Flutter GitHub Wiki

진짜 어려웠다.. Android Emulator - flutter_emulator_2_5554 2023-03-04 19-42-14

main.dart

import 'dart:io';

import 'package:dict/page/mainPage.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';

void main() async {
  runApp(const MyApp());
}

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

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

page/mainPage.dart

import 'package:dict/model/dict.dart';
import 'package:dict/widget/dict_card.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';

class mainPage extends StatefulWidget {
  const mainPage({super.key});

  @override
  State<mainPage> createState() => _mainPageState();
}

class _mainPageState extends State<mainPage> {
  Dio dio = Dio();
  Dict? dict;
  search(String query) async {
    //함수호출 할 때 어떤 단어 입력했는지 넘기려고
    var url = "https://api.dictionaryapi.dev/api/v2/entries/en/";
    try {
      var res = await dio.get(url + query);
      var data = res.data.first; //데이터 대상
      dict = Dict.fromMap(data); //새로 생성된 값 저장
      setState(() {}); //새로고침
    } catch (e) {
      dict = null; //만약 서버에 없는 단어이면 null 넣고 화면 새로고침
      setState(() {});
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Dictionary App'),
        elevation: 0,
        centerTitle: false,
      ),
      body: Center(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch, //자식위젯이 모든 영역 가짐
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Row(
              children: [
                Expanded(
                  child: Padding(
                    padding: const EdgeInsets.all(16),
                    child: TextField(
                      decoration: const InputDecoration(
                        hintText: "Search",
                        suffixIcon: Icon(Icons.search),
                        enabledBorder: OutlineInputBorder(
                          borderSide: BorderSide(color: Colors.white),
                        ),
                        focusedBorder: OutlineInputBorder(
                          borderSide: BorderSide(color: Colors.white),
                        ),
                      ),
                      onSubmitted: (value) {
                        search(value); //함수호출 (value에 단어 들어가 있음)
                      },
                    ),
                  ),
                ),
              ],
            ),
            Divider(),
            if (dict != null)
              Expanded(
                  child: SingleChildScrollView(
                      child:
                          DictCard(dict: dict!))), //처음들어오면 null이기 떄문에 if로 거르고
            //이제 null이 아니면 데이터가 있다고 !붙이기
          ],
        ),
      ),
    );
  }
}

model/definition.dart

class Definition {
  String definition;
  List<String> synonyms;
  List<String> antonyms;
  String? example; //예시 없을 수도 null-safety

  Definition({
    required this.definition,
    required this.synonyms,
    required this.antonyms,
    required this.example,
  });

  factory Definition.fromMap(Map<String, dynamic> map) {
    return Definition(
        definition: map['definition'],
        synonyms: List<String>.from(map['synonyms']),
        antonyms: List<String>.from(map['antonyms']),
        example: map['example']);
  }
}

model/dict.dart

import 'package:dict/model/phonetic.dart';

import 'license.dart';
import 'meaning.dart';

class Dict {
  String word;
  String? phonetic; //발음기호가 없는 단어는 null이 될 수 있다
  List<Phonetic> phonetics;
  List<Meaning> meanings;
  License license;
  List<String> sourceUrls;

  Dict({
    required this.word,
    required this.phonetic,
    required this.phonetics,
    required this.meanings,
    required this.license,
    required this.sourceUrls,
  });

  factory Dict.fromMap(Map<String, dynamic> map) {
    return Dict(
        word: map['word'],
        phonetic: map['phonetic'],
        phonetics: List<Phonetic>.from(map['phonetics']
            .map((e) => Phonetic.fromMap(e))), //리스트라 phonetic이라는 클래스로 바꾸고 넣어야돼
        //map함수로 List<dynamic>을 Map<String,dynamic>으로
        meanings: List<Meaning>.from(
            map['meanings'].map((e) => Meaning.fromMap(e))), //phonetics랑 똑같아
        license: License.fromMap(map['license']), //데이터형 바꿔
        sourceUrls: List<String>.from(map['sourceUrls']));
  }
}

model/license.dart

class License {
  String name;
  String url;

  License({
    required this.name,
    required this.url,
  });

  factory License.fromMap(Map<String, dynamic> map) {
    return License(name: map['name'], url: map['url']);
  }
}

model/meaning.dart

import 'definition.dart';

class Meaning {
  String partOfSpeech;
  List<Definition> definitions;

  Meaning({
    required this.partOfSpeech,
    required this.definitions,
  });

  factory Meaning.fromMap(Map<String, dynamic> map) {
    return Meaning(
      partOfSpeech: map['partOfSpeech'],
      definitions: List<Definition>.from(map['definitions']
          .map((e) => Definition.fromMap(e))), //리스트 다이나믹으로 바꾸기
    );
  }
}

model/phondetic.dart

import 'package:dict/model/license.dart';

class Phonetic {
  String? text; //텍스트가 없을 수 있다
  String? audio;
  String? sourceUrl; //없을 수 있다
  License? license; //license가 없을 수도

  Phonetic({
    required this.text,
    required this.audio,
    required this.sourceUrl,
    required this.license,
  });

  factory Phonetic.fromMap(Map<String, dynamic> map) {
    return Phonetic(
        text: map['text'],
        audio: map['audio'],
        sourceUrl: map['sourceUrl'],
        license: map['license'] != null
            ? License.fromMap(map['license'])
            : null); //라이센스 클래스 주려고
    //null일 수 도 있는데 fromMap에서 오류 삼항연산자로 체크
  }
}

widget/dict_card.dart

import 'package:dict/model/dict.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';

import 'meaning_card.dart';

class DictCard extends StatelessWidget {
  const DictCard({super.key, required this.dict});
  final Dict dict;

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              dict.word,
              style: TextStyle(fontWeight: FontWeight.bold, fontSize: 22),
            ),
            const Divider(),
            ListView.builder(
              physics: const NeverScrollableScrollPhysics(), //스크롤 기능 없애기
              shrinkWrap: true,
              //렌더링 두번 위해 listView사용
              itemBuilder: ((context, index) {
                return MeaningCard(meaning: dict.meanings[index]);
              }),
              itemCount: dict.meanings.length,
            )
          ],
        ),
      ),
    );
  }
}

meaning_card.dart

import 'package:dict/model/meaning.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';

class MeaningCard extends StatelessWidget {
  const MeaningCard({super.key, required this.meaning});
  final Meaning meaning;

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Column(
        children: [
          Text(
            meaning.partOfSpeech,
            style: TextStyle(fontWeight: FontWeight.bold),
          ),
          ListView.builder(
            shrinkWrap: true,
            scrollDirection: Axis.vertical,
            physics:
                const NeverScrollableScrollPhysics(), //없을 때 커스텀 위젯으로 표현하면 또 오류
            itemCount: meaning.definitions.length,
            itemBuilder: ((context, index) {
              return ListTile(
                title: Text(meaning.definitions[index].definition),
              );
            }),
          ),
        ],
      ),
    );
  }
}
⚠️ **GitHub.com Fallback** ⚠️