Understanding the RenderObject System

Flitter uses the same rendering architecture as Flutter. To draw something on the screen, you need to understand three tree structures.

Widget Tree → Element Tree → RenderObject Tree

Three Tree Structures

Widget is the blueprint, Element is the instance, and RenderObject handles the actual rendering

Widget Tree
설계도 (불변 객체)
Element Tree
인스턴스 (상태 관리)
RenderObject Tree
실제 렌더링 (레이아웃 & 페인팅)
// Widget Tree (개발자가 작성하는 코드)
Container({
  child: Text("Hello")
})

// Element Tree (프레임워크가 자동 생성)
ContainerElement -> TextElement

// RenderObject Tree (실제 렌더링)
RenderDecoratedBox -> RenderParagraph

Role of Each Tree

Widget Tree (Blueprint)

  • Immutable objects that declaratively express UI structure
  • Code written by developers
  • Can be recreated every frame

Element Tree (Instance)

  • Intermediate layer connecting Widget and RenderObject
  • Manages state and handles lifecycle
  • Elements are reused even when Widgets change

RenderObject Tree (Rendering)

  • Handles actual layout calculation and drawing
  • Contains size, position, and painting information
  • Performance-critical part, reused whenever possible

Separation of Layout and Paint

Layout and Paint Process

performLayout() calculates size and position, paint() does the actual drawing

Layout Phase
performLayout()
1. 자식 크기 측정
2. 자신의 크기 결정
3. 자식 위치 결정

Layout Phase

performLayout() {
  // 1. 자식에게 제약 전달
  child.layout(constraints);
  
  // 2. 자신의 크기 결정
  size = computeSize(child.size);
  
  // 3. 자식 위치 결정
  child.offset = computeOffset();
}

Paint Phase

paint(context, offset) {
  // 1. 배경 그리기
  context.drawRect(rect, paint);
  
  // 2. 자식 그리기
  child.paint(context, childOffset);
  
  // 3. 전경 그리기
  context.drawBorder(border);
}

performLayout(): Size and Position Calculation

class RenderBox {
  performLayout() {
    // 1. Perform layout for children
    // 2. Determine own size based on children's sizes
    // 3. Determine children's positions
  }
}

paint(): Actual Drawing on Screen

class RenderBox {
  paint(context: PaintingContext, offset: Offset) {
    // 1. Draw own content (background, borders, etc.)
    // 2. Request paint from children
  }
}

Why Are They Separated?

Layout and Paint are separated for performance optimization:

  1. Layout Caching: Layout is not recalculated if size or position doesn’t change
  2. Partial Repaint: Only paint is performed without layout when only colors change
  3. Layer Optimization: Unchanged parts are cached as layers

Exploring the Source Code

Flitter’s RenderObject implementation can be found in the packages/flitter/src/renderobject/ directory:

  • RenderObject.ts: Base RenderObject class
  • RenderBox.ts: RenderBox implementing 2D box model
  • RenderFlex.ts: Flex layout that forms the basis of Row and Column

Looking at the actual implementation, you can see it has almost identical structure to Flutter.

Next Steps

Now that you understand the basic concepts of RenderObject, in the next chapter we’ll explore the Constraints system, which is the core of layout. We’ll examine in detail how constraints are passed from parent to child and how sizes are determined.