Flutter로 반응형 개발자 포트폴리오 웹사이트(앱) 구축

무언가를 배우는 가장 좋은 방법은 행동하는 것입니다.
그리고 자신만의 개발자 포트폴리오를 구축해야 한다면 직접 구축하지 않겠습니까!

이 튜토리얼에서는 Flutter로 반응형 개발자 포트폴리오 웹사이트/앱을 구축하는 방법을 단계별로 알려 드리겠습니다. 이 튜토리얼을 따르면 배우게 될 것입니다 -
  • Flutter로 반응형 UI를 구축하는 방법.
  • ScrollController을 사용하고 프로그래밍 방식으로 스크롤하는 방법.

  • 내용의 테이블


  • What we'll build
  • Live Demo
  • Video Explanation
  • Creating Project
  • Initial Setup
  • Directory Setup
  • Creating HomePage
  • Creating The Navbar Section
  • Creating endDrawer
  • Creating Components of HomePage
  • Creating Project Model
  • Source Code

  • 우리가 만들 것

    We are going to build a portfolio app with mainly 4 sections about , skills , projects and contact . For making our app responsive we'll use media query.

    라이브 데모

    If you are so excited to see what we'll build like me, you can see the live demo of app Here . 이 웹 버전 데모는 html 렌더러를 사용하여 배포됩니다.
    Live Demo

    비디오 설명

    At the time of writing this post. It was getting too long so I added this video explanation section.
    If you want to watch video tutorial of this post you can watch it from here.

    프로젝트 생성

    Supposing flutter is installed and initial setup is done in your system.
    If you have't installed then you can get it from
    here
    VS Code 또는 Android Studio에서 명령 팔레트를 사용하거나 터미널에 다음 명령을 입력하여 새 플러터 프로젝트를 만듭니다.flutter create <YOUR PROJECT NAME>

    초기 설정

    Now careate a new folder in your project assets
    Inside the assets folder create a subfolder images

    Add an image that you want to show on your portfolio, in your images folder.
    Your image should be placed like this
    assets/images/

    Now load images in pubspec.yaml file

    assets:
        - assets/images/
    

    Clear everything from main.dart file and write the following code.

    import 'package:flutter/material.dart';
    import 'package:portfolio_app/pages/home_page.dart';
    
    void main() => runApp(const MyApp());
    
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          debugShowCheckedModeBanner:false,
          home: HomePage(),
        );
      }
    }
    

    디렉토리 설정

    Inside the lib folder create 3 new directory named components , models , pages .

    -lib
       - components
       - models
       - pages
    

    홈페이지 만들기

    As you can see in the above code we have used HomePage in the home of MaterialApp lets create it.
    Inside the pages directory create a new file homepage.dart .
    Create a stateless widget HomePage in it like below.

    import 'package:flutter/material.dart';
    
    class HomePage extends StatelessWidget {
      HomePage({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          //Add Key
          appBar: AppBar(
            title: const Text(
              'JANE DOE',
              style: TextStyle(
                fontSize: 22,
                color: Color(0xFF4756DF),
                fontWeight: FontWeight.bold,
              ),
            ),
            backgroundColor: Colors.white,
            elevation: 2,
          ),
          body: SafeArea(
            child: Stack(
              children: [
                SingleChildScrollView(
                //Add Scroll Controller
                  child: Column(
                    children: const [
    
                    ],
                  ),
                ),
              ],
            ),
          ),
        );
      }
    }
    

    Now we need to create a GlobalKey and a ScrollController .

    GlobalKey - for opening and closing the end drawer that we'll use later.
    ScrollController - for scrolling to a specific section of page.

    final ScrollController myScrollController = ScrollController();
    final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
    

    add the _scaffoldKey in the Scaffold widget and myScrollController in the SingleChildScrollView.

    Navbar 섹션 만들기

    Because we have to create a responsive UI we'll show the navbar inside the endDrawer of Scaffold on small screen and inside the actions of AppBar on large screen.

    Inside the components directory caret a new file home_page_actions.dart and write the following code.

    import 'package:flutter/material.dart';
    import 'package:portfolio_app/utils.dart';
    
    class HomePageActions extends StatelessWidget {
      final ScrollController sc;
      const HomePageActions({Key? key, required this.sc}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        bool isMobile = Utils.isMobile(context);
        return isMobile
            ? Column(
                children: getWidgets(sc, context, isMobile: true),
              )
            : Row(
                children: getWidgets(sc, context),
              );
      }
    
      List<Widget> getWidgets(ScrollController sc, BuildContext context,
          {bool isMobile = false}) {
        int scrollDur = isMobile ? 800 : 500;
        return [
          Padding(
            padding:
                EdgeInsets.symmetric(horizontal: 10, vertical: isMobile ? 20 : 0),
            child: TextButton(
              onPressed: () {
                if (isMobile) Navigator.pop(context);
                sc.animateTo(
                  200,
                  duration: Duration(milliseconds: scrollDur),
                  curve: Curves.easeIn,
                );
              },
              child: const Text(
                'About',
                style: TextStyle(
                  fontSize: 17,
                  color: Color(0xFf4756DF),
                  fontWeight: FontWeight.w600,
                ),
              ),
            ),
          ),
          Padding(
            padding:
                EdgeInsets.symmetric(horizontal: 10, vertical: isMobile ? 20 : 0),
            child: TextButton(
              onPressed: () {
                if (isMobile) Navigator.pop(context);
                sc.animateTo(
                  isMobile ? 1100 : 800,
                  duration: Duration(milliseconds: scrollDur),
                  curve: Curves.easeIn,
                );
              },
              child: const Text(
                'Skills',
                style: TextStyle(
                  fontSize: 17,
                  color: Color(0xFf4756DF),
                  fontWeight: FontWeight.w600,
                ),
              ),
            ),
          ),
          Padding(
            padding:
                EdgeInsets.symmetric(horizontal: 10, vertical: isMobile ? 20 : 0),
            child: TextButton(
              onPressed: () {
                if (isMobile) Navigator.pop(context);
                sc.animateTo(
                  1400,
                  duration: Duration(milliseconds: scrollDur),
                  curve: Curves.easeIn,
                );
              },
              child: const Text(
                'Projects',
                style: TextStyle(
                  fontSize: 17,
                  color: Color(0xFf4756DF),
                  fontWeight: FontWeight.w600,
                ),
              ),
            ),
          ),
          Padding(
            padding:
                EdgeInsets.symmetric(horizontal: 10, vertical: isMobile ? 20 : 0),
            child: TextButton(
              onPressed: () {
                if (isMobile) Navigator.pop(context);
                sc.animateTo(
                  isMobile ? 2600 : 1900,
                  duration: Duration(milliseconds: scrollDur),
                  curve: Curves.easeIn,
                );
              },
              child: const Text(
                'Contact',
                style: TextStyle(
                  fontSize: 17,
                  color: Color(0xFf4756DF),
                  fontWeight: FontWeight.w600,
                ),
              ),
            ),
          )
        ];
      }
    }
    

    There are lots of things in the above code but we'll see only the important one.

    As you can see we have used Utils class so lets create it.

    Inside the lib create a new directory called utils.dart and write the following code.

    import 'package:flutter/cupertino.dart';
    
    class Utils {
      static bool isMobile(BuildContext context) {
        return MediaQuery.of(context).size.width <= 600;
      }
    
      static double mdqh(BuildContext context) {
        return MediaQuery.of(context).size.height;
      }
    
      static double mdqw(BuildContext context) {
        return MediaQuery.of(context).size.width;
      }
    }
    

    the isMobile method returns true if the screen width of device is less than or equal to 600 pixel, you can decide your own logic for that.

    mdqh method returns the height of screen
    mdqw method return the width of screen

    These utilities will help us to make UI responsive.

    Now go to HomePage and inside the AppBar of Scaffold add the following code.

    actions: [
              Utils.isMobile(context)
                  ? Padding(
                      padding: const EdgeInsets.only(right: 10),
                      child: IconButton(
                        icon: const Icon(
                          Icons.menu,
                          color: Color(0xFf4756DF),
                          size: 30,
                        ),
                        onPressed: () {
                          _scaffoldKey.currentState!.openEndDrawer();
                        },
                      ),
                    )
                  : HomePageActions(
                      sc: myScrollController,
                    ),
            ],
    

    and in the Scaffold of HomePage add the endDrawer

    endDrawer: Utils.isMobile(context)
              ? MyDrawer(
                  sc: myScrollController,
                )
              : null,
    

    now lets create our MyDrawer widget

    endDrawer 만들기

    Inside the components create a new file my_drawer.dart and write the following code

    import 'package:flutter/material.dart';
    import 'package:portfolio_app/components/home_page_actions.dart';
    
    class MyDrawer extends StatelessWidget {
      final ScrollController sc;
      const MyDrawer({Key? key, required this.sc}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            backgroundColor: Colors.transparent,
            elevation: 0.0,
            leading: IconButton(
              onPressed: () {
                Navigator.pop(context);
              },
              icon: const Icon(
                Icons.close,
                color: Color(0xFF4756DF),
              ),
            ),
          ),
          body: Center(child: HomePageActions(sc: sc)),
        );
      }
    }
    

    You can see we are reusing the HomePageActions again here and it will be visible only on the small screen, remember the code that we wrote in it.

    Now inside the HomePage Scaffold add the floating action button that will help to scroll at top.

     floatingActionButton: FloatingActionButton(
            mini: Utils.isMobile(context) ? true : false,
            onPressed: () {
              myScrollController.animateTo(
                0,
                duration: const Duration(milliseconds: 800),
                curve: Curves.easeIn,
              );
            },
            child: Image.network(
              'https://eager-williams-af0d00.netlify.app/assets/icons/icons8-upward-arrow.gif',
            ),
          ),
    

    animateTo method of ScrollController will scroll the page to the specified position will nice animation you can define the duration and curve for the animation.

    The same method we are using in the HomePageActions buttons to scroll at a specific section using a calculated height.

    If I write the complete code the article will be too long and boring. So lets quickly complete our project. You can find the source code in the last section

    홈페이지 구성요소 생성

    Now in the HomePage inside the children of column add the remaining components.

    children: const [
    Header1(),
    MoreAboutMe(),
    SizedBox(height: 50),
    TopSkills(),
    SizedBox(height: 50),
    RecentProjects(),
    SizedBox(height: 50),
    ContactForm(),
    SizedBox(height: 50),
    Footer(),
    SizedBox(height: 20),
    ],
    
    You can get the code of these components from the Here .

    이제 HomePage에서 사용한 childrenStack의 맨 아래에 마지막으로 다음 컴포넌트를 추가합니다.

    const SocialIconsBar(),
    


    프로젝트 모델 생성

    In the RecentProjects() component we need Projectmodel so
    in the models directory create a new file called project_model.dart and write the following code.

    lass ProjectModel {
      final String imgURL;
      final String projectName;
      final String? shortDescription;
      final String actionLink;
    
      ProjectModel(
          {required this.imgURL, required this.projectName, this.shortDescription, required this.actionLink});
    }
    

    Create a new file inside the lib called constants.dart and create some ProjectModels/Demo Projects.

    import 'package:portfolio_app/models/project_model.dart';
    
    class Constants {
      static final List<ProjectModel> projects = [
        ProjectModel(
          actionLink: '#',
          imgURL:
              'https://eager-williams-af0d00.netlify.app/assets/images/expenseTracker.png',
          projectName: 'Expense Tracker',
        ),
        ProjectModel(
          actionLink: '#',
          imgURL:
              'https://eager-williams-af0d00.netlify.app/assets/images/netflixClone.png',
          projectName: 'Netflix Clone',
        ),
        ProjectModel(
          actionLink: '#',
          imgURL:
              'https://eager-williams-af0d00.netlify.app/assets/images/greenyEarth.png',
          projectName: 'Greeny Earth',
        ),
    

    And we have successfully created our responsive developer portfolio with flutter 🎉

    소스 코드

    You can see/download the source code from github.
    Repo Link

    감사!

    좋은 웹페이지 즐겨찾기