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, and RenderObject Tree
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
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:
- Layout Caching: Layout is not recalculated if size or position doesn't change
- Partial Repaint: Only paint is performed without layout when only colors change
- 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 classRenderBox.ts: RenderBox implementing 2D box modelRenderFlex.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.