Flutter

[Flutter] Hello Flutter~🖐

mSubWay 2024. 3. 12. 10:07

네이티브 앱 프레임워크는 운영체제(OS)와 직접 소통을 한다.

하지만 Flutter 나 Dart 는 운영체제와 직접 소통하지 않고 Flutter 엔진을 통해 소통한다. 

그렇기 때문에 여러 플랫폼에서 보여줄 수 있다.

예를들어 Flutter에서 button 위젯을 그린다는것은 네이티브 앱의 것이 아니라 Flutter 엔진에 의해 그려지는 것이다.

Engine 을 통해 Embedder(운영체제) 와 소통하여  그 운영체제의 화면에 Dart로 생성한 UI를 그려줄 수 있게 되는 것이다.

 

Flutter 는 모두 위젯으로 되어있다. 모든 위젯은 Class 이다.

runApp 은 앱의 최초 시점이다.

 

MaterialApp : 구글 디자인 

CupertinoApp : 애플 디자인

 

Scaffold : 기본적인 뼈대를 뜻함

ㄴ 그 아래로 위젯들을 나열한다. 위젯은 뼈대 안에 들어가는 부품들이다.

 

위젯 생성시 const 를 붙여주면 컴파일 하는 중에 값을 산정할 수 있어서 앱 성능이 좋아지므로 권장되고 있다.

- settings.json 수정

ㄴ "editor.codeActionsOnSave" : { "source.fixAll" : true } 를 추가하면 작업 파일 내에서 자동으로 const 가 추가된다.

ㄴ "dart.previewFlutterUiGuides" : true 를 추가하면 작업 파일 내에서 위젯들의 부모관계를 명확하게 알 수 있는 라인이 생긴다.(저장 후 vscode 를 껏다켜야 적용됨)

ㄴ "[dart]" 안에 "editor. formatOnSave": true 로 되어있다면 작업 파일을 저장했을때 자동으로 코드를 정렬하고 콤마도 찍어준다.

 

* 필요 Extensions

- Flutter

- Dart

- Error Lens : 코드에서 바로 에러가 뭔지 알려준다.

 

Code Action

ㄴ 위젯에 랩핑을 통해 다른 위젯으로 감싸고 싶을때, 위젯을 커스텀 위젯으로 만들고 싶을때 등에 사용

ㄴ 위젯을 더블 클릭하여 커서를 올리면 왼쪽 라인숫자가 써있는 곳에 💡전구가 생긴다. 전구를 클릭하면 랩핑을 할 수 있는 위젯들이 나온다. 랩핑된 위젯을 제거 할 수도 있다.

 

Row 위젯

ㄴ main : 가로, cross : 세로

Column 위젯

ㄴ main : 세로, cross : 세로

 

Stateless Widget

- 단지 build 메서드를 통해서 UI를 출력할 뿐이다.

 

Stateful Widget

- 데이터가 변경될때마다 변화를 실시간으로 UI에 반영하고 싶을때 사용

- stateful 은 state 형태의 또 다른 클래스 가지고 있는데, 이는 위젯의 데이터와 UI를 저장하고, 데이터가 변경되면 UI도 변경된다.

- Stateful 을 상속받은 class 는 상태를 가지고 있다.

- State<Stateful 을 상속받은 class> 는 데이터와 위젯의 UI를 가지고 있다. 그래서 State의 데이터가 바뀔때 위젯의 UI도 새로운 데이터와 함께 새로고침된다.

ㄴ setState 함수를 통해 State 에게 데이터가 변경되었다고 알려줄 수 있다. (인터랙티브=대화형)

ㄴ 데이터가 변경되었음을 알게된 build 메서드는 재실행되면서 UI에 표현된다.

ㄴ setState 함수는 자주 사용하지는 않는다. ( 대부분 위젯을 사용하여 처리한다.)

ㄴ Stateful 위젯은 라이프사이클을 가지고 있다. initState(), dispose()

ㄴ 만약 Stateless 위젯이 초기화시에 받은 프로퍼티 값은 직접적으로 사용이 불가하고 build 시에만 사용이 가능하다. 그래서 직접 사용하고 싶다면 Stateful 로 변경하여 사용이 가능하다. State 를 가지게 되므로 이 별도의 state 클래스에서 접근이 가능(widget.[data]) 하게 되어 사용이 가능해진다.

 

BuildContext

- 부모에 접근하기 위해

- context 는 부모 요소의 모든 정보를 가지고 있다.

 

Flexible Widget

- UI 비율에 맞춰 유연하게 만들 수 있게 해준다.

 

# Dart 와 Flutter 패키지 설치 문서

https://pub.dev/

 

http 

- http 통신을 위한 패키지

💡yaml 파일에 추가하여 설치시 제대로 설치되지않을때 

ㄴ 터미널을 통해 설치하면 해결됨

ㄴ 또 작업파일에서 import 가 자동으로 되지 않았을때 http.dart 패키지를  직접 import 한다. (보통 as http 로 alias 를 붙여 alias 를 사용한다.)

ㄴ get 함수는 Future 타입을 리턴 받는다.

(💡Future 는 미래에!!! 받을 값의 타입을 알려줘!! 라는 의미이다.)

ㄴ await 키워드 : 결과값을 기다릴 때 사용 

ㄴ 따라서 await 는 async 함수에서 사용된다.  즉 await-async 는 비동기 작업에서 사용된다. 

ㄴ 비동기가 필요한 로직이라면 http 가 아니더라도 직접 커스텀으로 만든 class의 반환형을 Future로 사용하여 비동기 구조를 만들 수 있다.

 

FutureBuilder

: future 로 받은 데이터를 UI에 전달할 수 있는 방법 

: Future의 builder 는 필수이고, UI를 그려주는 함수이다.

: 데이터가 변경될 UI에 상태를 변경하고 싶다면 Stateful 을 사용해야 하지만, FutureBuilder를 통해 Stateless 로도 UI에 상태를 변경해주는것이 가능하다. 

: builder에 있는 snapshot 를 통해 Future의 상태를 알 수 있어서, await - async 를 안 써줘도 상관없다. 

 

ListView :  한번에 모든 아이템들을 로딩하고 있어서 많은 메모리를 사용하게 된다.

ListView.builder : ListView 의 최적화, 사용자가 보고 있는 섹션만 로딩하기 위함.

 

Navigator

: Stateless 위젯을 애니매니션 효과로 감싸서 스크린처럼 보이도록 하겠다는거다.

: 따라서 Navigator.push 에 넣어줘야하는건 route 라서 MaterialPageRoute 로 Stateless 위젯을 감싸서 route 로 만들어서 사용한다.

: Navigator 를 사용하는 이유는 애니매이션 효과를 이용해서 다른 페이지로 이동했다는 느낌을 가지게 할 수 있다.

 

 

State Management

setState

: 하나의 위젯에서만 사용하고, 다른 위젯에 넘기려면 생성자를 통해야 한다.

* 넘기려는 state 가 위젯트리 상에서의 관계가 저~~ 멀리 있는 위젯이라면 계속 생성자를 생성해야하는 비효율적으로 넘기는 구조가 된다. 그래서 필요한게  Provider이다.

 

Provider 

: Provider 역시 위젯이다!

: Provider.of<데이터모델>(context)

*of 메서드는 주어진 context를 거슬러 올라가면서 가장 가까이에 있는 원하는 타입의 인스턴스를 찾아서 반환하라는 의미이다.

: 최상위 위젯을 Provider(위젯)로 감싸서 create 에 데이터를 세팅하게되면 위젯트리 상에 있는 모든 하위 위젯들이 접근할 수 있게된다.

 

ChangeNotifier

: with 를 통해 ChangeNotifier 의 프로퍼티와 메서드를 사용할 수 있다.

: ChageNotifier 클래스를 listen (=바라보고=구독하고) 있는 모든 위젯들에게 데이터가 변경될때마다 알려줄 수 있다.

: 위젯들이 listen 할 수 있는 방법

addListener 를 통해서 필요한 위젯 내에서 콜백 메서드를 등록하면 된다.

addListener 는 자동으로 dispose 되지 않기 때문에 remveListener 를 통해 필요없어진 addListener 를 dispose 시켜줘야한다.

데이터 인스턴스를 매번 생성자를 통해서 전달해줘야한다.

addListener 는 데이터가 변경되었다는 것을 알려주긴 하지만 자동으로 UI를 변경시켜주진 않는다.

그래서 나온게 ChangeNotifierProvider 이다.

 

ChangeNotifierProvider

: 모든 위젯들이 listen 할 수 있는 ChangeNotifier 인스턴스를 생성할 수 있다.

: addListener 는 자동으로 dispose 된다.

: Provider.of 를 통해 위젯들이 쉽게 ChangeNotifier 인스턴스에 접근할 수 있게 해준다.

: 자동으로 UI 를 변경해주고, 필요시 데이터가 변경되는 건 알고 싶지만 UI 변경은 원치 않을 경우 listen: false 라는 기능을 제공한다.

 

MultiProvider

: 여러개의 Provider 가 계층 구조를 이룬다면 하위의 하위의 하위의 하위에 계속 Provider 를 감싸게 되어 가독성 및 효율성이 떨어진다. 

: providers 에 Provider 들을 세팅에 줌으로써 하위의 모든 위젯들이 원하는 Provider에 접근이 가능해진다. 

 

GetX 패키지

: Simple State Manager (GetBuilder)

: ChangeNotifierProvider 와 거의 비슷하다.

: 사용법 예제

ㄴ state 관리를 해주기 위해 Controller 라는 클래스에 GetController 라는 클래스를 상속받아야한다.

ㄴ 위젯에서는 Controller 타입의 controller 변수를 선언하고, Get.put() 메서드를 가져오고 그 안에 dependency 로 Controller 를 등록하는데 이는 Controller 인스턴스를 메모리에 등록시켜주는 역할을 하는 것이다.

* DI 는 데이터class 의 프로퍼티와 메서드에 접근할 수 있게 인스턴스를 생성하는것이다.

ㄴ 변한 state 를 화면에 다시 그려주는 역할을 하는 GetBuilder (위젯) 를 사용한다.

ㄴ GetBuilder 는 어떤 타입의 데이터를 사용할지 아직 모르고 있기 때문에 GetBuilder<Controller> 이렇게 타입을 가지고 있어야한다.

GetBuilder 위젯 하위에 원하는 UI 를 그려준다.

ㄴ UI 에서는 controller 변수를 통해 Controller 에 접근이 가능해진다. 

!! 이때 UI 에 변경이 가능해지려면 메서드에서는 GetxController 에 있는 update() 메서드를 실행해줘야 UI에 변경이 이루어 진다. 이렇기 때문에 setState 와 비슷하다. 그래서 UI 를 변경시 수동으로 컨트롤 해줘야한다.

ㄴ GetBuilder 에는 init 이라는 인자가 있다. 이는 Get.put 을 통해 Controller 인스턴스를 메모리에 등록해주는 일 init을 통해서 직접 가능하게끔 해준다. 따라서 init 에 Controller() 인스턴스를 넣어주면 Get.put은 필요없어지고, UI에서는 Get.find() 를 통해 직접 인스턴스를 찾아주는데, 어떤 클래스인지 알 수 없으므로 Get.find<Controller>() 이렇게 타입을 지정하여 접근이 가능해진다.

 

 

: Reactive State Manager

ㄴ state 를 바로바로 반영해주는 매니저 = async 방식

ㄴ 지속적으로 state 가 변하는걸 Observable=listen 하고 있는다.

ㄴ GetBuilder

: Observable 의 변화를 listen 하지 않음

: 수동으로 UI 를 리빌드해야하기 때문에 반드시 update 메서드를 호출해야함.

: GetBuilder 도 자체적으로 Controller인스턴스에 initialize 할 수 있다.

ㄴ GetX, Obx 는 Stream 데이터 사용 

ㄴ Obx

: Observable(obs) 의 변화를 listen 함

: Controller 인스턴스가 미리 다른 곳에 initialize 되어 있어야함.

ㄴ GetX

: Observable(obs) 의 변화를 listen 함

: 자체적으로 Controller 인스턴스 initialize 할 수도 있음

: Obx 보다 다양한 기능을 내장하고 있어서 좀 더 무거움(미비함)