Flutter_차근차근_2주차

이안이다·2023년 10월 4일
0

Flutter

목록 보기
5/7
post-thumbnail

2.3 Hello World

기본으로 주어졌던 이 화면 코드들을 싹 다 날리고!

import 'package:flutter/material.dart';

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

이렇게만 남기면서 본격적으로 실습을 시작해보자 !

widget

widget은 레고 블록과 같다고 생각하면 된다. 플러터로 UI를 만드는 것도 레고 블럭들을 합쳐서 완성작을 만들듯이 윗젯들을 합쳐서 만든다. Flutter 공식 홈페이지나 각종 사이트에서 수 많은 widget들이 제공된다. 어떤 기능들이 있고 어떤 윗젯들을 써야하고 이런 걸 외울 필요는 없다. 다만 내가 실습을 하거나 개발을 하다가 필요한 기능이 생기면 구글에 검색해서 widget을 찾아서 사용하면 된다. (진짜 엄ㅁㅁㅁ청 많은 widget들이 있다!)

위에 첨부된 사진들에서도 +버튼도 하나의 widget이고, 가운데 문구도 widget, 숫자도 widget, 상단 디자인 툴바도 모두 하나의 widget이다.

widget을 만든다는 건 하나의 class를 만든다는 것과 같다. 코드로 해보자!

class App extends StatelessWidget{
  
  Widget build(BuildContext context) {
    // TODO: implement build
    throw UnimplementedError();
  }
}

App이라는 클래스를 만들건데 이 자체로는 의미가 없다. Widget을 써야하는데 가장 기초적인 widget인 StatelessWidget을 사용하기 위해 이를 상속 받아왔다. 그리고 이 때 꼭 기억해야 하는 것이 있는데 바로 build다. VS code에서 build를 치면 자동으로 완성해주는데 이 build는 내가 코드로 만든 내용들을 화면에 나타나게 해주는 역할이고 이거 없으면 에러뜬다. build 기억하자!

import 'package:flutter/material.dart';

void main() {
  runApp(App());
}

class App extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('플러터 빠이팅!!!!'),
        ),
        body: Center(
          child: Text('플러터 빠이팅!!!!'),
        ),
      ),
    );
  }
}

실습코드 완성! 확실히 애뮬레이터를 그냥 web으로 하니까 느리기도 하고 심심하다..ㅜㅜ
무난하게 강의 보면서 따라갈만 했는데 기억했으면 하는 Flutter의 규칙 하나가 있다.

규칙은 화면이 scaffold라고 하는 걸 가져야 된다는 거다. scaffold는 우리 화면의 구조를 제공해준다. 모바일 앱의 모든 화면은 scaffold가 필요하다. scaffold는 네이게이션 바, 상단 버튼, 중앙 정렬 등등을 다 가능하게 해준다. scaffold도 하나의 Widget이다 !!!

appBar부분, body부분, child부분 등등 모두 Widget을 사용하는 거임! 윗젯천국이네,,,

VS code에서 제공해주는 자동 완성 기능이나, 커서를 올렸을 때 볼 수 있는 옵션들을 한 번씩 훑어보면서 따라가면 도움이 많이 될 것 같다. 특히 코드 포맷팅 해주는 거 완전 땡큐


3 UI CHALLENGE

3.0 Header

import 'package:flutter/material.dart';

void main() {
  runApp(App());
}

class App extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Color(0xFF181818),
        body: Padding(
          padding: EdgeInsets.symmetric(
            horizontal: 40,
          ),
          child: Column(
            children: [
              SizedBox(
                height: 80,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.end,
                children: [
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: [
                      Text(
                        'Hey, Selena',
                        style: TextStyle(
                          color: Colors.white,
                          fontSize: 28,
                          fontWeight: FontWeight.w800,
                        ),
                      ),
                      Text(
                        'Welcome back',
                        style: TextStyle(
                          color: Color.fromRGBO(255, 255, 255, 0.8),
                          fontSize: 18,
                        ),
                      ),
                    ],
                  )
                ],
              )
            ],
          ),
        ),
      ),
    );
  }
}

실습 코드를 짰다!
사실 나도 니콜라스처럼 코드를 만질 때마다 실시간으로 렌더링 되는 실습 환경을 원하지만...
Web으로 실습하는거라 한 번 코드를 수정해서 실행할 때마다 3~40초씩은 기다려야하는 번거로움이 커서 원하는만큼 이거저거 만들어보지 못해서 아쉽다...

VS Code에서 참 요긴한 기능을 많이 제공해주는 것 같다. 이렇게 배경색을 고를 때도 커서만 올리면 자동으로 shade까지 단계별로 고르게 해준다. shade값이 높을수록 더 찐한 해당색이 된다.
CSS처럼 Opacity로 투명도를 조절 할 수 있다.

플러터는 왜 레고블록과 같다고 설명했는지 이해가 된다. 하나의 블록을 깔아놓고, 그 위에 또 다른 블록을 쌓고 또 위에 쌓는 식으로 만들어 나간다. 코드만 봐도 그렇듯!!

자 '으라차차'를 처음에 만들었을 때는 화면 최상단 좌측에 이상하게 낑겨있었는데 이를 자연스럽게 위치시키기 위해서는!
MainAxizAlignment는 수평방향
CrossAxisAlignment는 수직방향
이 두개의 option들을 조절해서 내가 원하는 위치로 옮길 수 있다.

CSS에서 padding을 조절하는 거랑 동일하게 padding을 조절하고 말 그대로 디자인 하는 거라 이해하기도 쉽고 재밌게 실습했다!


3.1 Developer Tools

코드 길이만 보면 끔찍하다. 파이썬이나 JAVA라고 생각했으면 이정도만 돼도 애법 복잡한 코딩이었을텐데...

MainAxizAlignment는 수평방향
CrossAxisAlignment는 수직방향
이게 row가 기준이냐 column이 기준이냐에 따라 서로 반대이기 때문에 헷갈리지 않게 잘 기억해야한다 !

그리고 이번 강의에서 배운 것 바로 이 버튼 !!

코드가 점점 길어질수록 많은 widget들을 사용하게 될텐데 복잡한 구조들을 보기 쉽게 해주는 개발자 도구이다. 근데 그냥 크롬에서 F12눌러서 보는거랑 똑같다. 진짜 똑같음.


3.2 Buttons section

재사용 가능한 Widget에 대해서 배운다.

지금 실습 화면을 보면 '야인마!!'위로 빈 공간이 있는데 위에 코드에서처럼 SizedBox로 채워놨다. Row로 줘서 가로로 쭉 한 칸을 차지하게 해서 빈 공간을 만들어둔거다. 자 그럼 실습 기릿

import 'package:flutter/material.dart';

void main() {
  runApp(App());
}

class App extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: Color(0xFF181818),
        body: Padding(
          padding: EdgeInsets.symmetric(
            horizontal: 40,
          ),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              SizedBox(
                height: 80,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.end,
                children: [
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: [
                      Text(
                        '야 인마 !!!!',
                        style: TextStyle(
                          color: Colors.white,
                          fontSize: 28,
                          fontWeight: FontWeight.w800,
                        ),
                      ),
                      Text(
                        '어서와~~~ ^_^',
                        style: TextStyle(
                          color: Color.fromRGBO(255, 255, 255, 0.8),
                          fontSize: 18,
                        ),
                      ),
                    ],
                  )
                ],
              ),
              SizedBox(
                height: 120,
              ),
              Text(
                'Total Balance',
                style: TextStyle(
                  fontSize: 22,
                  color: Colors.white.withOpacity(0.8),
                ),
              ),
              SizedBox(
                height: 5,
              ),
              Text(
                '\$523 903 332 3766',
                style: TextStyle(
                  fontSize: 48,
                  fontWeight: FontWeight.w600,
                  color: Colors.white,
                ),
              ),
              SizedBox(
                height: 30,
              ),
              Row(
                children: [
                  Container(
                    decoration: BoxDecoration(
                      color: Colors.amber,
                      borderRadius: BorderRadius.circular(45),
                    ),
                    child: Padding(
                      padding: EdgeInsets.symmetric(
                        vertical: 20,
                        horizontal: 50,
                      ),
                      child: Text(
                        'Transfer',
                        style: TextStyle(
                          fontSize: 20,
                        ),
                      ),
                    ),
                  )
                ],
              )
            ],
          ),
        ),
      ),
    );
  }
}

자 열심히 코드 따라왔고,
결과는 !!!

실습은 돈이 조금 부족해보여서 여유 있게 잔고를 채워줬다. ^^
코드가 진짜 길어서 어려워 보이지만 사실 실습하면서 썼던 코드들을 복사해서 그대로 재탕하는 부분들이 많았기 때문에 길이만 길지 난이도가 높진 않다 !

실습코드를 따라가면서 느낀 건 아직까진 익숙하지 않아서 그런지 CSS랑 자주 헷갈린다. 근데 CSS는 Selection을 골라서 스타일들을 연결해주는 식이었지만 이건 직접 레고블록 쌓듯이 차곡차곡 꾸미고 따라서 위에 만든거에 또 꾸며주고 하는 방식이라 디자인하는 구조의 차이는 분명한 것 같다.


3.3 VSCODE SETTING

강의 따라가면서 계속 느끼던 불편함인데 VS code에서 파란줄을 자꾸 어마어마하게 띄우던 것.. 컴파일 시에 별 문제가 없어서 그냥 무시했지만


생각보다 짜증나고 신경쓰였다,,, 고맙게도 이번 영상에선 이 파란줄들에 대해서 다룬다!

근데 나는 그냥 안고 갈래. 설정 만지는 거 PTDS와서 그냥 이 상태라도 유지하고 싶어서 함부로 만질 자신이 없다...


3.4 Code Actions

자, 예를들어서 item으로 가득찬 아주 큰 Column하나가 있는데 거기에 padding값을 주고 싶다고 가정해보자. 모두 잘라내서 padding을 다 추가하고 실수 없이 그 안에 하나씩 ㅗ두 붙여넣기가 되도록 신중하게 노가다 뛰는 수밖에 없다.

그럴 때 할 수 있는 좋은 방법이 있다. 이렇게 마우스를 Text라는 아이템 위에 올려두면 전구가 이렇게 뜨는데 요놈을 클릭하면 일종의 리팩토링 actions인 Code Actions를 보여준다. 이번 강의에서 배우는게 바로 이 개념!

이런식으로 code actions가 뜬다. 예를들어 Container를 쓰면 코드가 깔끔하게 감싸진다고 한다. 마찬가지로 이 유용하고 많은 option들을 외울 필요는 없다. 하지만 어떤 기능들이 있는지는 알아두면 나중에 활용하기 편할 것 같다 !

많이 사용되는 위젯 감싸기 옵션들을 정리해둔 표다 !
그리고 단축키를 활용해서 만드는 프로그램에서 가장 많이 사용되는 옵션을 지정해둘 수도 있고 전구를 눌렀을 때 나오는 옵션 리스트들의 순서도 내가 임의로 변경할 수 있다는 점도 기억해두자잇


3.5 Reusable Widgets

이번 강의 개념 전에 유용한 VS Code Extention하나를 소개해준다.

요녀석인데 딱 이름과 아이콘에서부터 느낌이 오듯이 에러 메시지를 바로바로 보여준다. 예를 들어서 padding위젯을 사용했을 때 위젯에 깜빡하고 padding값을 안넣어줬다면 컴파일 했을 때 에러가 뜨는 게 아니라 바로 코드 상에서 빨갛게 에러를 미리 탐지해준다.
다른 파이썬이나 자바같은 언어로 개발할 때도 사용할 수 있는지 궁금해서 검색해봤는데 다 가능한 것 같다 ! 왜 이걸 이제야 알았지!? 지금 나처럼 불리한 개발환경에서 시간 많이 들여서 따라가는 입장에서는 시간을 배로 아껴줄 수 있는 좋은 녀석인듯하다 ㅎㅎㅎㅎ

자 어쨌든 이번 강의의 본론은 Resuable Widgets다. 말 그대로 재탕하는 윗젯인건데!! 실습 먼저 열심히 따라하고 정리하자~~

import 'package:flutter/material.dart';
import 'package:toonflix/widgets/button.dart';

void main() {
  runApp(App());
}

class App extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: const Color(0xFF181818),
        body: Padding(
          padding: const EdgeInsets.symmetric(
            horizontal: 20,
          ),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const SizedBox(
                height: 80,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.end,
                children: [
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: const [
                      Text(
                        '야 인마 !!!',
                        style: TextStyle(
                          color: Colors.white,
                          fontSize: 28,
                          fontWeight: FontWeight.w800,
                        ),
                      ),
                      Text(
                        '어서와 ~~~ ^_^',
                        style: TextStyle(
                          color: Color.fromRGBO(255, 255, 255, 0.8),
                          fontSize: 18,
                        ),
                      ),
                    ],
                  )
                ],
              ),
              const SizedBox(
                height: 120,
              ),
              Text(
                'Total Balance',
                style: TextStyle(
                  fontSize: 22,
                  color: Colors.white.withOpacity(0.8),
                ),
              ),
              const SizedBox(
                height: 5,
              ),
              const Text(
                '\$523 903 332 3766',
                style: TextStyle(
                  fontSize: 48,
                  fontWeight: FontWeight.w600,
                  color: Colors.white,
                ),
              ),
              const SizedBox(
                height: 30,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: const [
                  Button(
                    text: 'Transfer',
                    bgColor: Color(0xFFF1B33B),
                    textColor: Colors.black,
                  ),
                  Button(
                    text: 'Request',
                    bgColor: Color(0xFF1F2123),
                    textColor: Colors.white,
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

그리고 새로 widget이라는 폴더를 생성하고 안에 button.dart파일을 만들어서 아래와 같이 코드를 추가로 짰다.

import 'package:flutter/material.dart';

class Button extends StatelessWidget {
  final String text;
  final Color bgColor;
  final Color textColor;

  const Button({
    super.key,
    required this.text,
    required this.bgColor,
    required this.textColor,
  });

  
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        color: bgColor,
        borderRadius: BorderRadius.circular(45),
      ),
      child: Padding(
        padding: const EdgeInsets.symmetric(
          vertical: 20,
          horizontal: 50,
        ),
        child: Text(
          text,
          style: TextStyle(
            color: textColor,
            fontSize: 20,
          ),
        ),
      ),
    );
  }
}

이렇게 코드를 짜면 !!

이렇게 결과가 나온다.

새로운 개념이나 이론들 보다는 이미 배웠던 내용들을 토대로 디자인을 하는 과정이라서 강의 시간도 길고 코드도 길어져도 딱히 내용 자체가 어렵지는 않았던 것 같다.
지난 Dart 강의에서 Player클래스로 여러 실습을 해봤던 것들과 그 클래스들에 다양한 프로퍼티들을 추가해주는 작업으로 디자인을 진행했다.


3.6 Card

import 'package:flutter/material.dart';
import 'package:toonflix/widgets/button.dart';

void main() {
  runApp(App());
}

class App extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: const Color(0xFF181818),
        body: Padding(
          padding: const EdgeInsets.symmetric(
            horizontal: 20,
          ),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const SizedBox(
                height: 80,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.end,
                children: [
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: const [
                      Text(
                        'Hey, Ian',
                        style: TextStyle(
                          color: Colors.white,
                          fontSize: 28,
                          fontWeight: FontWeight.w800,
                        ),
                      ),
                      Text(
                        'Welcome back',
                        style: TextStyle(
                          color: Color.fromRGBO(255, 255, 255, 0.8),
                          fontSize: 18,
                        ),
                      ),
                    ],
                  )
                ],
              ),
              const SizedBox(
                height: 120,
              ),
              Text(
                '잔고',
                style: TextStyle(
                  fontSize: 22,
                  color: Colors.white.withOpacity(0.8),
                ),
              ),
              const SizedBox(
                height: 5,
              ),
              const Text(
                '\$523 903 332 3766',
                style: TextStyle(
                  fontSize: 48,
                  fontWeight: FontWeight.w600,
                  color: Colors.white,
                ),
              ),
              const SizedBox(
                height: 30,
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: const [
                  Button(
                    text: 'Transfer',
                    bgColor: Color(0xFFF1B33B),
                    textColor: Colors.black,
                  ),
                  Button(
                    text: 'Request',
                    bgColor: Color(0xFF1F2123),
                    textColor: Colors.white,
                  ),
                ],
              ),
              const SizedBox(
                height: 100,
              ),
              Row(
                crossAxisAlignment: CrossAxisAlignment.end,
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  const Text(
                    'Wallets',
                    style: TextStyle(
                      color: Colors.white,
                      fontSize: 36,
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                  Text(
                    'View All',
                    style: TextStyle(
                      color: Colors.white.withOpacity(0.8),
                      fontSize: 18,
                    ),
                  ),
                ],
              ),
              const SizedBox(
                height: 20,
              ),
              Container(
                decoration: BoxDecoration(
                  color: const Color(0xFF1F2123),
                  borderRadius: BorderRadius.circular(25),
                ),
                child: Padding(
                  padding: const EdgeInsets.all(30),
                  child: Row(
                    children: [
                      Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          const Text(
                            'Euro',
                            style: TextStyle(
                              color: Colors.white,
                              fontSize: 32,
                              fontWeight: FontWeight.w600,
                            ),
                          ),
                          const SizedBox(
                            height: 10,
                          ),
                          Row(
                            children: [
                              const Text(
                                '6 428',
                                style: TextStyle(
                                  color: Colors.white,
                                  fontSize: 20,
                                ),
                              ),
                              const SizedBox(
                                width: 5,
                              ),
                              Text(
                                'EUR',
                                style: TextStyle(
                                  color: Colors.white.withOpacity(0.8),
                                  fontSize: 20,
                                ),
                              ),
                            ],
                          )
                        ],
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

자 dart.main코드를 열심히 따라갔다고 생각하고 컴파일 한 순간!!

에러가 등장했다.

코드에는 문제가 없는 것 같아서 한참 고민했는데 문제는 바로 const로 item들을 만들면서 내가 px크기를 정해놓은 부분들과의 충돌이었다. 실습을 web창에서 하기 때문에 발생한 부분 같다. 정사이즈인 전체화면으로 해놓고 Ctrl+0으로 100%배율을 맞췄더니

에러가 없어진 걸 볼 수 있다.

그리고 또 하나 깨달은 점.

그렇다고 모든 과정을 반응형으로 만들 수도 없기에 앞으로 전체화면으로라도 어떻게든 따라갈테다..

이번 강의에서도 계속 디자인에 집중해서 UI를 만들어 나갔다. padding과 margin을 계속 조정하고 각 요소들의 색상을 만졌다. 이번에는 솔직히 하다보니까 조금 지루했다..


Icons and Transforms

실습하다가 대참사가 발생했다.

Overflow가 발생하는데 애뮬레이터로 쓰던 chrome웹에서 확대 축소가 안 되고 애초에 강의에서 코드를 짤 때 에뮬레이터 상에서 아이콘들이 레이아웃을 벗어나거나 오버플로우 되지 않게 하기 위해서 고정값으로 size를 지정하기 때문에 그냥 web으로는 다 담을 수가 없기 때문일 거라 생각한다..

고민 끝에 내린 결론은 그냥 안고 가야하거나 스터디 때 같이 웹으로 실습하고 있는 희건이에게 어떻게 하고 있는지 물어서 적절히 타협해봐야할 것 같다.

TransformationWidget Transform.scale은 child를 필요로 한다. 하지만 child만 넣어준다고 되는 건 아니다. scale도 꼭 같이 설정해줘야하는데 없으면 에러가 난다.

이렇게 scale도 내가 원하는 값으로 설정해줄 수 있다. 강의대로 scale을 5로 했다가 엄청 커져서 당황했다.. ㅋㅋ

그리고 이 TransformationWidget을 통해서 자식 객체를 회전시킬 수도 있어서 예시 코드를 가져와봤다. 회전 말고도 Matrix4를 직접 지정해서 개발자 정의 변환 효과를 구현할 수도 있고, 마찬가지로 Matrix4를 이용하면 복잡한 행렬변환도 가능하다고 한다.

Transformation(
  transform: Matrix4.rotationZ(0.2), // 20도 회전
  alignment: Alignment.center,
  child: Container(
    width: 100.0,
    height: 100.0,
    color: Colors.blue,
    child: Center(
      child: Text("회전된 텍스트"),
    ),
  ),
)

진짜 CSS로 웹 꾸미는 거랑 똑같아서 그럭저럭 재밌다. 방법만 다를뿐,,


profile
경제와 개발을 곁들인 기획자..!

1개의 댓글

comment-user-thumbnail
2023년 11월 1일

너 왜 맨날 나빼고놀아

답글 달기