dev/프론트엔드

코드팩토리 flutter : 2장 - chap 4,5

wosrn 2024. 9. 16. 17:41

 - 플러터 프레임워크의 세 계층 : 임베더 계층(로우레벨) - 엔진 계층 - 프레임워크 계층
- 스키아 엔진 사용 : 대부분의 크로스플랫폼 앱 개발 프레임워크들은 웹뷰 혹은 각 플랫폼의 ui 라이브러리 사용 / 반명 플러터는 웹뷰를 사용하지 않고 직접 스키아 엔진을 사용하여 화면에 ui를 그려냄
- 이 때 새로 렌더링이 필요한 위젯들만 렌더링하기에 다른 크로스플랫폼 앱 개발 프레임워크에 비해 높은 성능
- rn의 경우, 자바스크립트 브릿지를 통해 플랫폼과 통신, 플랫폼의 ui를 그대로 사용
- 반명 플러터는 위젯을 스키아 엔진에 직접 그려내고, 필요한 제스처 및 이벤트를 브릿지를 통하지 않고 실행 - 더 빠름

 
플러터 프로젝트를 생성하고, 에뮬레이터 (기기 없이 테스트하는 가상머신 환경) 도 생성해주었다
 
그리고 겪은.. 에러 (인 줄 알았으나 아니였던 것)

 
위와 같이 에뮬레이터를 연결하고 main.dart를 run 했는데 휴대폰 배경화면만 보이고 앱이 실행이 안되는 것이었다
구글링도 열심히 해보았지만 에뮬레이터 자체가 연결이 안되는 경우에 대한 이야기만 있지, 연결이 되었는데 앱이 실행 안되는 경우는 잘 찾지를 못하여... 시간을 한참 쓰다가 깨달은 것
" 플러터 첫 앱 실행 시 꽤 오래 걸린다 " 
....
기다리면 되는 것이었다
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
계속 한 3초 기다리고 안되니까 중지하고 구글링하고.. 를 반복하다가
같은 동아리의 플러터 코어 언니에게 물어보니 기다려보라고 하여서,, 설마 ㅋㅋ (지금까지 에러인줄 알고 부딪히던게 사실 에러가 아니라 내 참을성 이슈...라고..?) 하는 마음으로 실행한 채로 좀 기다리다가 다시 보니 

 
이렇게 앱이 잘 실행되는 것이었다,,,^^
사실 에뮬레이터 연결에서도 유사한 이슈를 겪었는데, 디바이스 매니저에서 에뮬레이터를 실행해놓고 상단바의 에뮬레이터 선택 탭에 해당 에뮬레이터가 뜨지 않아서 open ~ 을 누르다가 중복으로 열면 안된다는 에러메세지를 마주했었는데.. 이 역시도 디바이스 매니저에서 에뮬레이터 실행 후 좀 기다리니까 상단바에도 자동으로 연결되는 것이 보였다
ㅋㅋㅋㅋ
인내심을 가지자...
 
이 이유로 저녁시간을 보내버린게 허무하지만... 심각한 에러가 아니라 다행이라고 생각하며,,,,^^ 이 챕터를 마저 공부해보자
 

기본 제공 코드를 지우고, 위의 코드만 남겼다
- main() 함수는 플러터 프로젝트가 실행되는 도입부이며, 따라서 플러터 프로젝트를 실행하면 가장 먼저 main() 함수가 실행되며 main() 함수 안에 runApp() 함수를 실행시켜 프로젝트를 시작한다. 
- material.dart는 머터리얼 디자인( 구글이 개발한 디자인 시스템으로, 일관된 사용자 경험과 직관적인 인터페이스를 제공하기 위해 만들어짐, 색상, 타이포그래피, 아이콘, 애니메이션 등 다양한 디자인 가이드라인을 포함함)과 관련된 기능을 불러오는 코드로, 이 파일을 불러와야 플러터가 기본제공하는 위젯을 사용 가능하다
- runApp 함수는 flutter가 기본적으로 제공하는 함수로,  WidgetsFlutterBinding.ensureInitialized()와 같은 초기화 작업을 처리하고, 주어진 위젯을 루트 위젯으로 설정하여 애플리케이션을 실행한다.
일반적으로 runApp은 MaterialApp이나 CupertinoApp과 같은 최상위 위젯(모든 하위 페이지나 구성요소를 최상단에서 담는 그릇) 을 받아서 애플리케이션의 UI를 구성하는 데 사용된다
- 위의 코드를 보면, runApp() 함수에 materialApp이라는 위젯을 추가하고, 그 안에 Scaffold라는 위젯을 추가했다
 - materialApp은 머터리얼 디자인 기반의 위젯들을 사용하게 해주는 위젯이다 : 테마 설정, 네비게이션 관리 등이 가능 - title, theme, home(제일 먼저 나올 페이지) 등을 설정 가능
- Scaffold는 머터리얼앱 다음으로 위치하는 위젯으로, Flutter에서 앱의 기본 시각적 구조를 정의하는 데 사용되는 위젯 -> 화면 전체를 차지하며 레이아웃을 도와주고 ui관련 특수 기능을 제공해줌 - 화면 알림 스낵바, 앱바(화면 상단바), 탭바 추가 등
- 보통 플러터에서 main() 함수 안에서 runApp()을 실행하고 그 안에 MaterialApp과 Scaffold 위젯을 추가하는 것이 기본 설정이라고 생각하면 됨 - 이 설정을 하고 나면 원하는 요소를 화면에 추가할 수 있다
+ 플러터에서는 마지막 매개변수 끝에 콤마를 추가하는 코딩 스탠다드가 있다
 
- 글자를 화면에 출력하기 위해 Text 위젯을 Scaffold에 추가해서 글자를 입력했음
- 이 글자를 가운데에 정렬하려면 center위젯을 사용한다

 
 
 
https://docs.flutter.dev/ui

 

Building user interfaces with Flutter

Introduction to user interface development in Flutter.

docs.flutter.dev

 
https://velog.io/@valorantjett0107/flutter-main-%ED%95%A8%EC%88%98-MaterialApp

 

flutter - main() 함수, MaterialApp

main() 함수, MaterialApp 대해 알아보자

velog.io

 
https://cbh2031.tistory.com/120

 

MaterialApp,Scaffold 간단하게 알아보기

플러터 프로젝트를 생성하면 MaterialApp() 속성을 통해 기본 색상, 폰트 등을 지정할 수 있습니다. MaterialApp( theme: ThemeData( primaryColor: Colors.blue, accentColor: Colors.orange, ), ) 3. 홈 화면 설정 => home 속성을

cbh2031.tistory.com

https://www.crypist.com/post/flutter/material/materialapp-class/

 

[플러터] 머티리얼 앱 가이드

Flutter의 MaterialApp 위젯을 통해 앱의 제목, 테마, 초기 화면, 내비게이션 등을 쉽게 설정하고 사용자 정의하는 방법을 알아보세요. 고품질 앱 개발 가이드.

www.crypist.com

https://blog.everdu.com/80

 

[Flutter] 2. 플러터의 위젯 & MaterialApp, Scaffold, AppBar 위젯

* 플러터를 원문 공식 문서 (https://flutter.dev/docs)를 읽으면서 공부하는 과정에서 정리하고자 작성하는 포스팅으로 저는 플러터 실무 개발 경력이 없는 대학생인 점을 미리 밝힙니다. * 추가로 오

blog.everdu.com

 
https://xentinn.tistory.com/44

 

[Flutter] main.dart 분석하기

1. import import 'package:flutter/material.dart'; Flutter의 핵심이라고 할 수 있는 material 라이브러리를 불러옵니다. material 라이브러리 안에는 Material Design 구현을 위한 많은 코드들이 들어있습니다. 그렇다

xentinn.tistory.com

 
 

<chap 5 - 기본 위젯 알아보기>

- 모든 것은 위젯이다 (구글에서 플러터를 소개하는 문구) : 플러터에서 화면에 보여지는 ui와 관련된 모든 요소는 위젯으로 구성되어 있음

- 위젯은 현재 주어진 상태(state)라는 데이터를 기반으로 어떤 ui를 구현할지를 정의한다

- 위젯 상태가 변경되면, 변경사항에 알맞게 변경된 ui를 다시 화면에 그려준다

- 이 때 플러터 프레임워크는, 기존 상태의 위젯과 새로운 상태의 위젯을 비교하여 ui 변화를 반영할 때 필요한 최소한의 변경사항만 산출해서 화면을 그려냄

- 위젯은 자식을 하나만 갖는 위젯 / 여럿 갖는 위젯으로 나뉨

- 자식을 하나만 갖는 대표적 위젯은 아래와 같고, 대체로 child 매개변수를 입력받음

Container 위젯 자식을 담는 컨테이너 역할, 배경색/너비/높이/테두리 등의 역할 할 수 있음
GestureDetecor 위젯 플러터에서 제공하는 제스처 기능을 자식 위젯에서 인식하는 위젯 - 탭/드래그/더블 클릭 같은 제스처 기능이 자식 위젯에 인식됐을 때 함수를 실행할 수 있음
SizedBox 위젯 높이/너비 지정하는 위젯, 컨테이너와 다르게 디자인적 요소는 적용할 수 없고, const 생성자로 선언 가능해서 퍼포먼스는 더 효율적

 

- 자식을 여럿 가질 수 있는 위젯은 children 매개변수를 입력받으며, 리스트로 여러 위젯 입력 가능

Column 위젯 children 매개변수로 입력된 모든 위젯들을 세로로 배치
Row 위젯 children 매개변수로 입력된 모든 위젯들을 가로로 배치
ListView 위젯 리스트 구현할 때 사용 / 입력된 위젯이 화면을 벗어나게 되면 스크롤이 가능해짐

 

- child와 children 매개변수에 지속적으로 하위 위젯을 입력하면, 트리처럼 위젯 계층이 정리된다

: 머터리얼앱-스캐폴드-column -> container/row->컬럼(->icon/text)/컬럼/컬럼

 

- children과 child의 차이 : 플러터는 위젯 아래에 위젯이 계속 입력되는 형태로 위젯트리를 구성하여 ui를 제작

-> child,children 매개변수는 위젯에 하위 위젯을 추가할 때 사용 (child는 위젯 하나만, children은 위젯 여러개 추가 가능)

- 대부분 위젯은 child, children 중 하나만 제공

 

 

- 위 예제의 경우, Center 위젯 사용 : child 매개변수에 입력된 위젯을 가운데 정렬해주는 기능 하는 위젯 - hello flutter라는 문구를 가진 text위젯을 가운데 정렬해준다

 

 

- 이번에는 Column 위젯을 사용해보았다 : body에 sizedbox를 넣고, 그 child로 Column을 넣어준 후 -> children에 코드 와 팩토리를 입력하였다 -> 이렇게하면 화며 중앙에 코드와 팩토리가 세로로 보인다

 

*번외로... 리액트만 쓰던 나에겐 정말 적응안되는 에뮬레이터 첫 실행 시간

 

gpt에게 물어보니 이런 차이가 있다고 한다

 

 

이번엔 MyApp을 아예 클래스로 빼고, 여러 위젯을 사용해보자

코드를 위와 같이 변경하고 hot reload를 해도 안되길래 찾아보니, 핫리로드로 변경이 반영 안될때는 hot restart를 해주면 된다. 주로 상태 변경, 코드 구조 자체의 변경, 플러그인 변경 등의 큰 변경이 있을때 필요한 듯 하다

hot restart는 하단의 run 메뉴에서 번개모양 아이콘(핫리로드) 옆에 있는 녹색 사각형 아이콘이다

 

아무튼 위의 코드를 다시 보면, runApp안에 들어갈 MyApp을 우선 별도의 클래스로 빼주었다

그 후 materialapp을 최상위 위젯으로 갖는 구조를 return하게 해주었다

- myApp 클래스는 statelessWidget을 상속받은 플러터 위젯이며, 상태가 변하지 않는 ui요소를 정의할 때 쓴다

- build 메소드는 위젯의 ui를 생성하는 메서드이다

- 그 밑으론 우리가 원래 하던 것처럼, 머터리얼앱-스캐폴드-센터-텍스트의 구조로 코드를 짜주고, text 위젯의 스타일 기능을 이용했다

- StatelessWidget은 build 메서드를 오버라이드하여 UI를 정의한다. build 메서드는 위젯 트리가 변경될 때마다 호출되어 UI를 업데이트한다.

- StatelessWidget 사용 방법은, StatelessWidget을 상속받아 새 클래스를 정의한 후 클래스에서 build 메서드를 오버라이드하여 UI를 구성하고, build 메서드에서는 다른 위젯들을 조합하여 UI를 구성한다

+ stateless위젯은 주로 변경되지 않는 데이터(단순히 텍스트나 이미지를 표시하는 경우), 정적 ui 등에 사용되고, 반면 stateful위젯은 사용자 입력에 따라 화면이 변화하는 등 상태 변경이 필요한 경우, 상태관리, 에니메이션과 동적 데이터 등을 사용하는 경우 주로 쓴다.

 

 

- 제스처 관련 위젯 : 사용자가 키보드로 글자를 입력하는 행위 외의 모든 입력을, 플러터에선 제스처라고 부른다

ex) 화면 탭하기 , 길게 누르기 등

- GestureDetector 위제은 모든 제스처를 매개변수로 제공해준다. 제스처 관련 위젯은 하위 위젯에 탭, 드래그처럼 특정 제스처가 입력되었을 때 이를 인지하고 콜백함수를 실행하는 구조이다

- 버튼 위젯은 크게, textbutton, outlinebutton, elevatedbbutton 이 있다

- 텍스트버튼의 예시이다. 이 전까지는 const 사용을 주의로 권장하기에 사용했으나,  onPressed 속성에 전달된 콜백 함수 () {}는 동적으로 실행되는 코드이므로 const로 선언할 수 없다고 하여 const 를 빼주었다

- onPressed의 { } 부분에 버튼 클릭 시의 동작을 입력해주면 된다

 

 

- GestureDetector 위젯 : 손가락으로 하는 여러 입력을 인지하는 위젯 -> 한번 탭, 두번 탭, 길게 누르기 등 여러 행위를 인식하여 콜백함수를 실행한다

- 각 행위마다 실행할 내용을 입력하고, 제스처디텍터 위젯의 child로 해당 제스처들과 그에대한 반응을 적용할 위젯을 입력해준다

- 위의 행위 외에도 수평/수직 드래그, 확대 제스처 등에 대한 실행 내용을 설정할 수 있다

 

- FloatingActionButton : 머터리얼 디자인에서 추구하는 버튼형태이다. scaffold와 함께 사용하면 어려움 없이 구현가능

 

 

<디자인 관련 위젯>

1. container 위젯 : 다른 위젯을 담는 데 사용 - 위젯의 너비와 높이를 지정, 배경이나 테두리 추가에 많이 쓴다

 

  • Container에 child가 없을 때: 주로 스타일링 또는 레이아웃 조정 용도로 사용됩니다. 예를 들어, 공간을 확보하거나 배경색을 설정하는 데 유용합니다.
  • Container에 child가 있을 때: 레이아웃을 구성하거나 스타일을 적용하여 위젯을 감싸는 데 사용됩니다.

2. SizedBox 위젯 : 일반적으로 일정 크기의 공가늘 공백으로 두고싶을 때 사용됨 - 컨테이너 위젯으로도 공백 만들 수는 있지만, const 생성자를 사용하면 SizedBox 퍼포먼스에서 이점을 얻을 수 있다. 특정 크기의 공백 만들기 / 간격 조정에 주로 사용된다

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('SizedBox Example'),
        ),
        body: Center(
          child: SizedBox(
            width: 100.0, // 너비 설정
            height: 100.0, // 높이 설정
            child: Container(
              color: Colors.blue,
            ),
          ),
        ),
      ),
    );
  }
}

 

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('SizedBox with Spacing Example'),
        ),
        body: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('First Text'),
            SizedBox(height: 20.0), // 위젯 사이의 간격 설정
            Text('Second Text'),
          ],
        ),
      ),
    );
  }
}

 

위는 공백 지정, 밑은 간격 조정에 사용한 예시이다. 컨테이너는 더 많은 스타일링 옵션을 제공하는 반면, sizedbox는 간단하게 크기나 간격을 조정할 때 사용한다

 

3. padding 위젯 : child 위젯에 여백을 제공할 때 사용 , padding위젯의 padding 매개변수는 EdgeInsets 라는 값을 입력해야 함, child 매개변수에 padding을 적용하고자 하는 위젯 입력가능

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Padding(
            padding: EdgeInsets.all(16.0), // 모든 방향에 16픽셀의 여백 추가
            child: Container(			//패딩을 적용할 자식으로 컨테이너 추가
              color: Colors.green,
              child: Text(
                'Hello with Padding!',
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 24.0,
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

 

패딩은 적용된 위젯이 차지하는 크기 내부에서 간격이 추가된다. 반면 위젯의 크기 바깥에 간격을 추가해주는 마진이라는 기능도 있다. 다만 마진은 자주 사용하지 않고, 따로 위젯이 존재하지 않으며 container 위젯에 추가할 수 있다

 

이렇게 코드를 짜면, 파란 컨테이너 바깥(즉 파란 컨테이너와 까만 컨테이너 사이)에 40의 마진이 적용되고, 파란 컨테이너의 자식인 패딩 위젯은 파란 컨테이너 내부에 16의 여백을 두고 빨간 컨테이너로 나타난다

 

4. SafeArea

- 노치가 있는 휴대폰에서 노치에 위젯이 가리는걸 방지하기 위해, SafeArea 위젯을 사용하면, 기기별로 따로 예외처리 하지 않고도 안전한 화면 영역에서만 위젯을 그릴 수 있다

 

<배치 관련 위젯>

 

1. Row 위젯 : children 매개변수를 통해 여러개의 위젯을 입력받아서, 가로를 주축으로 하여 가로로 자식위젯을 배치한다. 가로가 주축( MainAxisAlignment ), 세로가 반대축( CrossAxisAlignment )이 된다

- CrossAxisAlignment.center (교차축인 세로축이 중앙) 를 기준으로 하면, MainAxisAlignment가 start이면 왼쪽정렬, center이면 중앙정렬, end이면 끝에 정렬, spacebetween이면 자식 위젯 간격을 균등하게 정렬 등으로 정렬된다 (이때 세로를 기준으로는 모두 중앙에 위치)

- MainAxisAlignment.center를 기준으로(주축인 가로축의 중앙), CrossAxisAlignment가 start이면 화면 맨 위 중앙에 정렬, center이면 정중앙 정렬, end이면 세로축 끝에 정렬된다(가로로는 중앙, 화면 맨 밑에 위치) 

 

2. column위젯 : row 위젯과 주축/반대축이 반대라는 것 외엔 동일하다

 

3. flexible위젯 : row나 column에서 사용하는 위젯으로, flexible에 제공된 child가 크기를 최소한으로 차지하게 할 수 있다. 또한 flex 매개변수를 통해 각 flexible 위젯이 얼만큼의 비율로 공간을 차지할 지 지정할 수 있다

예) column 위젯의 자식으로 flexible 위젯이 두개 있고, 각 flex가 3,1이라면 세로로 3:1의 비율로 차지

 

4. expanded위젯 : flexible 위젯을 상속하는 위젯이다. column과 row에서 이 위젯을 쓰면 위젯이 남아있는 공간을 최대한으로 차지한다. flexible 위젯은 fit 매개변수로 FlexFit.tight(자식 위젯이 필요한 공간과 관계 없이 남은 공간 다 차지) 또는 FlexFit.loose(자식 위젯이 필요한 만큼의 공간만을 차지)를 입력할 수 있는데, expanded 위젯은 flexible위젯의 fit 매개변수를 tight로 기본 제공한 위젯이다. 

 

5. stack 위젯 : stack위젯은, 위젯들을 겹치는 기능 제공 - 플러터의 그래픽 엔진인 스키아 엔진은 2d이기 때문에, 겹친 두께를 표현하진 못하지만 이 위젯을 쓰면 위젯 위에 위젯을 올린듯한 효과를 줄 수 있다 (먼저 입력된 자식이 밑에 깔리고, 나중에 입력된 자식이 위에 겹쳐져서 올라가는 형태)