Foggy day

[Flutter] How Flutter renders Widgets? - Flutter가 위젯을 그리는 방법 본문

Flutter/Flutter widget

[Flutter] How Flutter renders Widgets? - Flutter가 위젯을 그리는 방법

jinhan38 2023. 3. 24. 19:31

 

 

 

이번 포스팅에서는 Flutter가 어떤 방식으로 위젯을 그리는지 알아보겠습니다.

 

 

1. Flutter 3개의 Tree

2. Widget tree

3. Element tree

4. RenderObject tree

5. 마무리

 

 

 

 

1. Flutter 3개의 Tree

Flutter에는 3개의 Tree가 있습니다. Widget tree, Element tree, RenderObject tree입니다. 3개의 tree는 재사용성을 이용해서 더 좋은 성능을 발휘하기 위한 구조입니다. 물론 개념적으로 tree가 있으며, 도식화는 할 수 있지만 개발자가 직접 코드로 작성할 필요는 없습니다. Flutter 개발자가 직접 손보는 것은 Widget tree입니다. 

 

 

 

2. Widget tree

Widget tree는 개발자가 사용하는 위젯들을 계층화한 것입니다. 아래 이미지는 공식 문서에 있는 Widget tree 예시입니다.

 

 

 

 

위 이미지의 위젯 트리를 실제 코드로 구현하면 다음과 같습니다.

Container안에 Row가 있습니다. Row에는 3개의 Column이 있는데 각 컬럼 안에는 Icon과 Container위젯이 하나씩 있습니다. Container위젯에는 Text가 들어가 있습니다. 

이렇게 UI/위젯들을 계층적으로 구조화한 것을 Widget tree라 합니다. 

@override
Widget build(BuildContext context) {
  return Container(
    child: Row(
      children: [
        Column(
          children: [
            const Icon(Icons.add),
            Container(
              child: const Text("text"),
            )
          ],
        ) ,
        Column(
          children: [
            const Icon(Icons.add),
            Container(
              child: const Text("text"),
            )
          ],
        ) ,
        Column(
          children: [
            const Icon(Icons.add),
            Container(
              child: const Text("text"),
            )
          ],
        ) ,
      ],
    ),
  );
}

 

 

 

3. Element tree

Element tree를 이해하기에는 어려움이 있었습니다. 설명 자료들이 추상적이고, 구체적으로 Element가 무엇인지를 설명하는 자료가 많이 없었습니다. 그래서 Element가 무엇인지 알아보고, 그다음에 Element tree의 역할을 제가 이해한 방식으로 최대한 쉽게 서술해 보겠습니다.

 

Element란 무엇인가?  

공식 문서에 따르면 Element는 Widget의 인스턴스라고 합니다(인스턴스에 대한 개념은 생략하겠습니다). 하지만 이렇게만 보면 제대로 이해가 되지 않았습니다. 그래서 Flutter framework를 하나하나 뜯어봤습니다. Widget 클래스를 자세히 살펴보니 Element는 Widget의 생성과 함께 createElement 함수로 생성하는 클래스였습니다. Widget 클래스를 상속받은 statelessWidget과 statefulWidget 또한 createElement 함수를 반드시 구현해야 합니다.

즉, Element는 위젯의 생성/삭제와 함께 붙어 다니는 클래스이며, 여러 정보들을 담고 있습니다.

 

Element의 역할은?

Element tree의 역할은 UI 계층구조(위젯트리)에 어떤 요소가 있는지 확인하고, 이러한 요소들 간의 관계를 관리, 변형 및 모핑 하는 작업입니다.  

버튼을 클릭하면 SizedBox위젯을 Container위젯으로 변경하는 로직을 구현했다고 가정해 보겠습니다. 이때 단순히 위젯만 변경한다고 UI가 업데이트되지 않습니다. 실행 중인 앱에서 정상적으로 SizedBox를 Container로 변경했다고 하더라도 이는 위젯 트리가 변경된 것뿐이지 화면이 변경된 것은 아닙니다. UI를 그려주는 역할은 RenderObject가 하는데 RenderObject에게 UI를 다시 그리라고 알려주기 위해 알려주는 역할을 Element가 합니다. 

StatefulWidget에서 화면을 업데이트하기 위해서는 setState() 함수를 호출해야 합니다. setState함수에서는 markNeedsBuild()  함수를 실행하는데 markNeedsBuild 함수는 Element 클래스에 있습니다. 이 Element는  StatefulWidget을 생성할 때 같이 생성한 Element입니다. Element의 markNeedsBuild 함수는 다시 scheduleBuildFor 함수를 호출합니다.

이러한 일련의 과정들을 거치면서 화면에 변경된 것들이 있다면 Element는 RenderObject에게 화면을 다시 그리라고 알려줍니다.

 

 

 

4. RenderObject tree

RenderObject tree(Render tree)는 위젯을 실제 화면에 그리는 역할을 합니다. RenderObject의 생성은 Element가 합니다.

Framework의 레이어를 보면 Widgets 바로 아래 Rendering 레이어가 있습니다.

 

 

Render 레이어는 레이아웃, 페인팅, 접근성 등을 처리합니다. Flutter는 모든 것이 위젯이라고도 하지만 화면에 보이는 것들은 사실 렌더 객체입니다. 렌더 객체는 완전히 위젯이 변경되지 않는 이상 같은 렌더 객체를 재사용합니다. 예를 들어 text의 문자나 color만 변경된다면 동일한 렌더 객체를 사용하고 수정이 필요한 것들만 수정합니다(RenderObject의 ID 동일). 하지만 Text를 Image로 바꾼다면 새로운 렌더 객체를 생성합니다(RenderObject의 ID 변경).

 

 

 

5. 마무리

Flutter는 Widget, Element, RenderObject를 한 쌍으로 하여 계층적 구조와 각각의 tree들을 만들고 있습니다. 이러한 체계 덕분에 불필요한 렌더링을 줄이고, 뛰어난 성능을 발휘할 수 있습니다. 또한 개발자에게는 오직 위젯 트리만 관여하게 함으로써 개발을 더욱 수월하게 해주고 있습니다.