[Flutter] 스나이퍼팩토리 Flutter 기초과정 (18)

GONG·2023년 4월 14일
0
post-thumbnail

18일차 과제 | 비밀듣는 고양이 앱 제작

과제 내용


  • Assignment
    • 제공되는 패키지 secrets_cat_sdk를 활용하여 다음의 기대 결과물을 따라 만드세요.
    • 이번 과제는 최대한 다음의 결과물과 다른 디자인으로 제작하는데 목표를 두세요.

  • Requirements
    • 앱 이름은 [비밀듣는 고양이]가 아닌 다른 이름으로 진행하세요.
    • 앱 내에서 사용될 폰트는 다음과 같습니다.
      • 플러터에 폰트 등록 방법을 검색하여 앱내에 적용할 수 있도록 하세요. neo.ttf
    • 매인 캐릭터 또한 다음의 링크에서 마음에 드는 이미지를 골라서 진행하세요.
    • 페이지들의 배경이미지는 다음의 링크에서 마음에 드는 이미지를 골라서 진행하세요.
    • 각 위젯별 애니메이션은 최소 3개 이상이 적용되어야 합니다. 이 때 적용되는 애니메이션은 자유입니다.
    • 페이지는 3개 이상입니다. 필수 페이지는 다음과 같습니다.
      • SecretPage : 비밀을 볼 수 있는 페이지며, 모든 비밀을 데이터로 불러오며 각 비밀은 페이지로 이루어짐.
      • AuthorPage : 모든 작성자(회원)을 볼 수 있는 페이지
      • UploadPage: 비밀을 업로드할 수 있는 페이지
    • 패키지를 설치하면 Author와 Secret 데이터타입을 사용할 수 있습니다.
      데이터와 데이터타입을 활용하여 최대한 위 결과물의 비슷하게 앱을 만들어보세요.

폰트 넣기

  • assets > fonts > 파일 넣기
  • pubspec.yaml fonts 주석 풀고 등록
  • 앱 전체에 폰트 적용

Figma

피그마 링크 👉 비밀먹는햄버거

코드

  • main.dart
    import 'package:first_app/homework/week4/day18/splash.dart';
    import 'package:flutter/material.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      
      Widget build(BuildContext context) {
        return MaterialApp(
          theme: ThemeData(fontFamily: 'neo'),
          home: SplashScreen()
        );
      }
    }
  • splash.dart
    import 'package:first_app/homework/week4/day18/secret_hamburger.dart';
    import 'package:flutter/material.dart';
    
    class SplashScreen extends StatefulWidget {
      
      _SplashScreenState createState() => _SplashScreenState();
    }
    
    class _SplashScreenState extends State<SplashScreen> {
      
      void initState() {
        super.initState();
        Future.delayed(
          Duration(seconds: 3), // 3초 동안 Splash Screen 표시
              () => Navigator.pushReplacement(
            context,
            MaterialPageRoute(builder: (context) => SecretHamburger()),
          ),
        );
      }
    
      
      Widget build(BuildContext context) {
        return Scaffold(
          body: Container(
            decoration: BoxDecoration(
              image: DecorationImage(
                image: AssetImage('assets/images/secret_hamburger/Splash.png'),
                fit: BoxFit.fill
              )
            ),
          )
        );
      }
    }
  • secret_hamburger.dart
    import 'package:first_app/homework/week4/day18/author_page.dart';
    import 'package:first_app/homework/week4/day18/upload_page.dart';
    import 'package:flutter/material.dart';
    
    import 'secret_page.dart';
    
    class SecretHamburger extends StatelessWidget {
      const SecretHamburger({Key? key}) : super(key: key);
    
      
      Widget build(BuildContext context) {
    
        List menu = ['비밀 보러가기', '작성자 구경', '비밀 알려주기'];
    
        return Scaffold(
          backgroundColor: Colors.white,
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Padding(
                  padding: const EdgeInsets.only(bottom: 50.0),
                  child: Image.asset('assets/images/secret_hamburger/main-icon.png'),
                ),
                Column(
                  children: List.generate(
                    menu.length, (index) => Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 50, vertical: 20),
                      child: ListTile(
                        leading: Image.asset('assets/images/secret_hamburger/hambuug.png'),
                        title: Text(menu[index]),
                        onTap: () {
                          switch(index) {
                            case 0:
                              Navigator.push(
                                context,
                                MaterialPageRoute(builder: (context) => SecretPage())
                              );
                              break;
                            case 1:
                              Navigator.push(
                                  context,
                                  MaterialPageRoute(builder: (context) => AuthorPage())
                              );
                              break;
                            case 2:
                              Navigator.push(
                                  context,
                                  MaterialPageRoute(builder: (context) => UploadPage())
                              );
                              break;
                          }
                        },
                      ),
                    ),
                  ),
                )
              ],
            ),
          ),
        );
      }
    }
  • secret_page.dart
    import 'package:animate_do/animate_do.dart';
    import 'package:flutter/material.dart';
    import 'package:secret_cat_sdk/api/api.dart';
    
    class SecretPage extends StatefulWidget {
      const SecretPage({Key? key}) : super(key: key);
    
      
      State<SecretPage> createState() => _SecretPageState();
    }
    
    class _SecretPageState extends State<SecretPage> {
    
      
      Widget build(BuildContext context) {
        return Scaffold(
          extendBodyBehindAppBar: true,
          appBar: AppBar(
            foregroundColor: Colors.black,
            backgroundColor: Colors.transparent,
            elevation: 0,
          ),
          body: Container(
            decoration: BoxDecoration(
                image: DecorationImage(
                    image: AssetImage(
                        'assets/images/secret_hamburger/SecretPage-background.png'),
                    fit: BoxFit.fill
                )
            ),
            child: Column(
              children: [
                SizedBox(height: 50),
                Expanded(
                  child: FutureBuilder(
                      future: SecretCatApi.fetchSecrets(),
                      builder: (context, snapshot) {
                        if(snapshot.connectionState == ConnectionState.done) {
                          return PageView.builder(
                            itemCount: snapshot.data!.length,
                            itemBuilder: (context, index) {
                              var author = snapshot.data![index].author ?? '익명';
                              return Padding(
                                padding: const EdgeInsets.all(50.0),
                                child: Center(
                                  child: Column(
                                    mainAxisAlignment: MainAxisAlignment.center,
                                    crossAxisAlignment: CrossAxisAlignment.center,
                                    children: [
                                      ListTile(
                                        leading: ZoomIn(child: SizedBox(child: Image.asset('assets/images/secret_hamburger/main-icon.png'))),
                                        title: FadeInLeft(child: Text(author.toString())),
                                      ),
                                      Padding(
                                        padding: const EdgeInsets.all(8.0),
                                        child: ZoomIn(
                                          child: Container(
                                            width: 200,
                                            height: 100,
                                            color: Colors.grey[200],
                                            child: Text(snapshot.data![index].secret),
                                          ),
                                        ),
                                      )
                                    ],
                                  ),
                                ),
                              );
                            }
                          );
                        }
                        return Container();
                      }
                  ),
                  ),
                Text('먹을게~', style: TextStyle(fontSize: 20),),
                SizedBox(height: 30,)
              ],
            ),
          ),
        );
      }
    }
  • author_page.dart
    import 'package:animate_do/animate_do.dart';
    import 'package:flutter/material.dart';
    import 'package:secret_cat_sdk/api/api.dart';
    
    class AuthorPage extends StatefulWidget {
      const AuthorPage({Key? key}) : super(key: key);
    
      
      State<AuthorPage> createState() => _AuthorPageState();
    }
    
    class _AuthorPageState extends State<AuthorPage> {
    
      
      Widget build(BuildContext context) {
        return Scaffold(
          backgroundColor: Colors.white,
          appBar: AppBar(
            foregroundColor: Colors.black,
            backgroundColor: Colors.transparent,
            elevation: 0,
          ),
          body: FutureBuilder(
            future: SecretCatApi.fetchAuthors(),
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.done) {
                return GridView.builder(
                  itemCount: snapshot.data!.length,
                  itemBuilder: (context, index) {
                    return Container(
                      child: Column(
                        children: [
                          Flexible(
                            child: ZoomIn(
                              child: snapshot.data![index].avatar != null
                                  ? Image.network(snapshot.data![index].avatar!)
                                  : Image.asset('assets/images/secret_hamburger/main-icon.png'),
                            ),
                          ),
                          SizedBox(height: 10),
                          FadeInLeft(child: Text(snapshot.data![index].username)),
                        ],
                      ),
                    );
                  },
                  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 3,
                    mainAxisSpacing: 10,
                    crossAxisSpacing: 10,
                  ),
                );
              }
              return LinearProgressIndicator();
            }
          ),
        );
      }
    }
  • upload_page.dart
    import 'package:flutter/material.dart';
    import 'package:secret_cat_sdk/api/api.dart';
    
    class UploadPage extends StatefulWidget {
      const UploadPage({Key? key}) : super(key: key);
    
      
      State<UploadPage> createState() => _UploadPageState();
    }
    
    class _UploadPageState extends State<UploadPage> {
      TextEditingController textController = TextEditingController();
      String hamText = '진짜\n나만 알고\n잇을게';
    
      
      Widget build(BuildContext context) {
    
        return Scaffold(
          resizeToAvoidBottomInset: false,
          backgroundColor: Colors.white,
          appBar: AppBar(
            foregroundColor: Colors.black,
            backgroundColor: Colors.transparent,
            elevation: 0,
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                SizedBox(height: 20),
                Container(
                  padding: EdgeInsets.symmetric(horizontal: 60),
                  child: Stack(
                    children: [
                      Image.asset('assets/images/secret_hamburger/UploadPage-burger.png'),
                      Padding(
                        padding: const EdgeInsets.only(left: 110.0, top: 20),
                        child: Align(
                          child: Text(hamText)
                        ),
                      )
                    ]
                  ),
                ),
                SizedBox(height: 50),
                Container(
                  width: 250,
                  height: 200,
                  decoration: BoxDecoration(
                    color: Colors.grey[200],
                    borderRadius: BorderRadius.circular(10),
                  ),
                  child: TextField(
                    controller: textController,
                    maxLines: null,
                    textAlignVertical: TextAlignVertical.top,
                    decoration: InputDecoration(
                      hintText: '비밀을 말해보렴!!!',
    
                      border: InputBorder.none,
                      contentPadding: EdgeInsets.all(10),
                    ),
                  ),
                ),
                SizedBox(height: 20),
                ElevatedButton(
                  onPressed: () async {
                    setState(() {
                      SecretCatApi.addSecret(textController.text);
                      textController.text = '';
                      ScaffoldMessenger.of(context).showSnackBar(
                        SnackBar(
                          content: Text('비밀 등록이 완료되었습니다.'),
                        ),
                      );
                      hamText = '헤헤\n뻥이지롱';
                      Future.delayed(Duration(milliseconds: 1500), () {
                        setState(() {
                          hamText = '진짜\n나만 알고\n잇을게';
                        });
                      });
                    });
                  },
                  child: Text('비밀 등록'),),
                Spacer()
              ],
            ),
          ),
        );
      }
    }
    gif

    벨로그 이미지 크기가 안줄여져요..........


구현 못한 기능

비밀먹는 햄버거를 디자인하면서 나름 핵심 기능이라 생각했던 비밀 페이지의 먹을게, 뱉을게 기능(먹뱉 기능)을 구현하지 못해서 아쉽습니다
다음 페이지로 이동하는 중에는 ‘먹을게~’, 이전 페이지로 이동하는 중에는 ‘뱉을게~’, 페이지가 이동중인 상태가 아니라면 ‘짜잔’ 텍스트를 보여주는 기능인데,
많은 시도 끝에 금요일엔 포기하고 주말에 수정을 해보기로 다짐했습니다…
앱이 자꾸 빨개져요………………………………………

profile
우와재밋다

0개의 댓글