dev/프론트엔드

코드팩토리 flutter : 3장 chap 8

wosrn 2024. 9. 18. 17:59

< chap 8 - 전자액자 만들기 >

- 이미지 5개를 롤링해보여주는 액자 앱을 만들 것이다

- 좌우 스와이프하여 이미지 변경이 가능하고, 이미지가 특정 시간이 지나면 자동으로 롤링되는 기능

- PageView 위젯 (가로 또는 세로로 스와이프해 화면에 보이는 위젯을 변경하도록 해줌) , Timer (주기적으로 작업 반복 시에 사용), StatefulWidget (지금까지 stateless위젯만 다뤘는데, 이번에 stateful 다뤄볼 것)

 

1. 사전지식 : 위젯 생명주기

- 위젯이 화면에 그려지는 순간부터, 삭제되는 순간까지의 주기를 의미

 

(1) StatelessWidget

- 지금까지 작성한 위젯들은 모두 이 형태였음.

- 해당 위젯을 사용하면, 생성자가 실행되어 build()함수를 필수로 오버라이드 하도록 함

- 플러터의 모든 위젯은 widget클래스를 상속하고, 이 클래스는 불변의 특성을 갖고있다

- 그러나 위젯 속성을 변경해야할 때가 있는데, (ex.생성자에 새로운 매개변수 입력) stateless 위젯은 불변이기에 한번 이미 실행된 인스턴스의 build()함수는 재실행되지 않음 -> 대신 인스턴스를 아예 새로 생성한 후 기존 인스턴스를 대체하여 변경사항을 화면에 반영해야함

 

 

stateful 위젯의 생명주기 - 출처 : https://betterprogramming.pub/stateful-widget-lifecycle-a01c44dc89b0

(2) StatefulWidget

- 외부에서 위젯 생성자의 매개변수를 변경해주면 위젯이 새로 생성되고 build()가 실행되는 것은 위와 같지만, 위젯 내부에서 자체적으로 build() 함수를 재실행해야할 때 이 위젯을 사용하면 된다

- stateless 위젯과 다르게, 위젯 클래스와 스테이트 클래스 2개로 구성되어있고, 생명주기가 더 복잡하다

- 3가지 생명주기 : '상태변경이 없는 생명주기', 'StatefulWidget 생성자의 매개변수가 변경되었을 때의 생명주기', 'State 자체적으로 build()를 재실행 할 때의 생명주기'

 

-> 1. 상태변경이 없는 생명주기 : 위젯이 화면에 나타나며 생성되고 화면에서 사라지는 과정 -> 중간에 위젯의 상태 변경 x

: stateful 위젯 생성자 실행 -> createState() 함수 실행 (필수로 오버라이드) -> stateful위젯과 연동되는 state를 생성 -> state가 생성되면 initState()가 실행됨 : 이 함수는 state가 생성되는 순간에만 실행되고 절대 다시 실행되지 않음 -> didChangeDependencies() 실행 : BuildContext가 제공되고, state가 의존하는 값이 변경되면 재실행됨 -> state의 상태가 dirty로 설정됨 : build()가 재실행되어야하는 상태를 의미 -> build()가 실행되고 ui가 화면에 반영됨 -> build()가 완료되면 상태가 clean으로 변함 / 화면에 변화가 없으면 이 상태를 계속 유지 -> 위젯이 위젯 트리에서 사라지면 deactivate()가 실행됨 : state가 일시적 혹은 영구적으로 삭제될 때 실행됨 -> dispose() 실행 : 위젯이 영구적으로 삭제

 

-> 2. StatefulWidget 생성자의 매개변수가 변경되었을 때 생명주기

- stateful위젯도 stateless 처럼 하나의 클래스임 -> 매개변수 입력 받을 수 있음

- 위젯이 생성된 후 , 삭제되기 전에 매개변수가 변경되면 아래 생명주기가 실행됨

: StatefulWidget 생성자 실행 -> State의 didUpdateWidget() 실행 -> state가 dirty로 변경 -> build() 실행 -> state 상태가 clean으로 변경 

 

-> 3. state 자체적으로 build()를 재실행할 때 생명주기

- stateless 위젯은 실행 이후 build()가 절대 자동으로 재실행되지 않는 반면, stateful위젯은 State 클래스의 setState() 함수를 실행해서 build() 함수를 자체적으로 재실행 할 수 있음

: setState() 실행 -> state가 dirty로 변경 -> build() 실행 -> state 상태가 clean으로 변경

 

 

2. 사전지식 : Timer 

- 타이머는 특정 시간이 지난 후에 일회성 또는 지속적으로 함수를 실행함

- 이번 플젝에선 Timer.periodic()을 사용해서 주기적으로 콜백함수를 실행할 예정

- Timer.periodic()은 주기와 콜백함수 2개를 매개변수로 입력받는다

- Timer의 생성자는 두개 ; Timer() - 기본생성자로, 첫 매개변수로 대기시간을 Duration으로 입력하고 두번째 매개변수에 기가닝 끝난 후 실행할 콜백함수 입력 / Timer.periodic()-네임드 생성자, 주기적으로 콜백함수 실행 시 사용, 매개변수 순서는 전자와 같음

 

 

https://fronquarry.tistory.com/16

 

[flutter] 플러터 StatefulWidget 라이프 사이클 (lifecycle)

StatefulWidget(스테이트풀 위젯) 의 라이프 사이클에 대해 알아보도록 하겠습니다. 라이프 사이클과 함께 각 사이클에서 호출되는 훅 메소드도 알아보도록 하겠습니다. StatefulWidget의 라이프사이클

fronquarry.tistory.com

 

 

3. 구현하기

 

- lib 폴더 아래에 screen 폴더를 만들고, 그 안에 위와같은 파일을 만든다

 

- 그리고 main.dart에 위에서 만든 홈스크린을 홈 위젯으로 등록한다 (머터리얼앱의 홈으로)

 

 

- 이제 PageView 위젯도 홈스크린에 등록 (페이지뷰 위젯은 머러리얼 패키지에서 기본제공)

- childeren 매개변숭 페이지로 생성하려는 위젯들을 넣어준다

- List의 map() 함수 사용

 

++ 에뮬레이터가 연결이 잘 안돼서 구글링을 하다가.. 사용중인 에뮬레이터 디바이스 옵션을 cold boot로 바꿔주니 좀 나아졌다

 

 

 

- 이제 이미지 슬라이더의 기본 ui가 구현되었다.

- SystemChrome 클래스는 시스템 ui의 그래픽 설정을 변경하는 기능을 해준다 : 상단바 색상 변경 등등

- 이를 사용하여 상단 바 색상을 다크모드로 설정해보았다. 이 외에도 앱의 풀스크린 모드 지정, 실행 방향 지정, 시스템UI 변경 시 콜백함수 실행 등이 가능하다

 

- 이제 타이머 클래스로 액자 자동 롤링 기능을 추가해보자

- 타이머를 추가하려면, 홈스크린을 스테이트풀로 변경해야함 : Stateless를 그대로 쓰면, 타이머를 등록 가능한 위치가 build() 밖에 없고, 이렇게 하면 위젯 생성시마다 (빌드 실행시마다) 새로운 타이머가 생성되어 메모리 릭이 생긴다. 반면 stateful위젯을 쓰면, initState()를 통해 state가 생성될 때 딱 한번만 타이머를 생성할 수 있다

 

 

- 코드를 위와 같이 변경하였다

- 우선 홈스크린은 스테이트풀 위젯을 상속받는 클래스로 하고, createState()를 오버라이드 해주었다 -> _HomeScreenState라는 상태 객체를 생성 (앞의 내용에서, createState()는 필수로 오버라이드 해야하는 함수로, stateful위젯과 연동되는 state를 생성한다고 배움) 다시말해 createState() 메서드는 _HomeScreenState 객체를 생성하여 반환하며, 이 객체가 실제 상태를 관리하고 UI를 업데이트한다

- State<HomeScreen> createState() 에서  State<HomeScreen>는 제네릭 문법으로, State<HomeScreen>는 HomeScreen 위젯의 상태를 관리하는 State 객체의 타입을 나타낸다

- _HomeScreenState 클래스는, 먼저 생성한 stateful위젯 클래스(HomeScreen)를 매개변수로 받는 state클래스를 상속한다 -> 앞에서 배운 것처럼 build 함수는 state에서 정의한다 (앞에서 배운 것처럼, 위젯 클래스와 스테이트 클래스 두개로 이뤄진 모습)

 

 

- 이제 dart.async 패키지를 불러와서 타이머를 사용해보자

- initState()를 오버라이드하면 stateful위젯 생명주기에서의 initState()를 사용할 수 있게 되며, 모든 initState()는 부모의 initState()를 실행해줘야한다. 

- 부모 함수 실행 후, 3초마다 timer를 등록한다

 

- 페이지뷰 위젯에선 컨트롤러를 사용하여 조작이 가능하다. 

 

-  State 클래스에 컨트롤러를 생성해준 후 , pageview위젯에 매개변수로 등록한다

- 이제 컨트롤러를 등록했으니, timer.periodic의 콜백함수를 변경하여 주기적으로 페이지가 자동으로 넘어가도록 구현한다 

 

stateful위젯 구현 방식을 다시 정리해보자면, 위젯 클래스와 스테이트 클래스를 나눠 구현하는 구조이다.

 

  • StatefulWidget 클래스:
    • 위젯의 구조속성을 정의
    • 상태를 관리할 State 객체를 생성하는 메서드인 createState()를 구현
    • **State**는 Flutter에서 상태를 관리하는 클래스이며, State<T>는 T 타입의 위젯의 상태를 관리하는 클래스를 정의, 즉, State<HomeScreen>은 HomeScreen 위젯의 상태를 관리하는 State 객체를 정의
    • 상태를 변경하지 않으며, 상태를 관리할 수 있는 State 객체를 생성하기 위해 createState() 메서드를 오버라이드
    • createState() 메서드
      • 역할: StatefulWidget의 상태를 관리할 State 객체를 생성
      • 리턴 타입: State<T> 타입의 객체를 반환. 여기서 T는 해당 State 객체가 관리할 위젯의 타입
  • State 객체
    • 역할: 위젯의 상태를 관리. 상태는 UI의 특정한 조건을 반영하는 데이터를 포함하고 있으며, 상태가 변경되면 UI가 다시 그려짐.
    • 상태 관리: State 객체는 setState() 메서드를 사용하여 상태를 변경하고, 이 변경 사항을 기반으로 UI를 업데이트 ( PageView 위젯의 경우는 컨트롤러를 통해 상태변경을 반영하므로 setState를 사용할 필요가 없었음)
  • State 클래스:
    • 위젯의 상태를 관리
    • 상태를 유지하며 UI를 구성하고 업데이트하는 로직을 구현
    • build() 메서드를 오버라이드하여 UI를 그림