RenderObject Tree — трећи ниво хијерархије у Flutter-у, одговоран за стварно рендеровање интерфејса на екрану. Сваки чвор овог стабла врши израчунавање димензија (layout) и цртање (painting), претварајући конфигурацију виџета у пикселе. За разлику од Widget Tree, RenderObject Tree се ствара једном и ажурира се само при промени геометрије или изгледа. Према Flutter API Reference, 2025, ефикасност RenderObject Tree директно одређује глаткоћу анимација и брзину реаговања апликације.
Главне тачке
RenderObject Tree — хијерархијска структура објеката за рендеровање која је стварна репрезентација интерфејса у меморији. Сваки RenderObject зна своје димензије, положај на екрану и уме да себе нацрта. За разлику од виџета, који су лагани и могу се поново креирати стотине пута у секунди, RenderObject — тежак објекат са директним приступом графичком конвејеру.
Пут од виџета до пиксела пролази три фазе: Widget Tree описује шта треба да буде на екрану; Element Tree управља животним циклусом; RenderObject Tree обавља стварни посао. Сваки RenderObjectWidget (нпр. Padding, Transform, CustomPaint) креира RenderObject који се додаје у стабло рендеровања. RenderBox — најраспрострањенији тип RenderObject-а, који се користи за 99% стандардних виџета.
RenderObject — апстрактна класа која дефинише интерфејс за layout и paint. Садржи референце на родитељски RenderObject и објекте деце, као и апстрактне методе: performLayout, paint и hitTest. Сваки конкретни RenderObject имплементира ове методе у складу са својим понашањем: RenderFlex распоређује простор између деце, RenderImage приказује слику, RenderParagraph приказује текст.
abstract class RenderObject {
RenderObject? parent;
Constraints constraints;
ParentData? parentData;
bool _needsLayout = true;
bool _needsPaint = true;
void performLayout();
void paint(PaintingContext context, Offset offset);
}
У овој поједностављеној структури, RenderObject садржи заставице _needsLayout и _needsPaint које означавају објекат као да захтева ажурирање. Када се Widget Tree промени, Element Tree означава одговарајуће RenderObject-е као „прљаве„ за layout или paint, и при следећем кадру Flutter извршава само неопходне операције.
Сваки RenderObject извршава две кључне фазе: layout (одређивање димензија и позиција) и paint (цртање). Ове фазе се извршавају у строгом редоследу: прво layout за цело стабло, затим paint. Фаза paint може бити изостављена ако се layout није променио, чиме се штеде ресурси GPU-а.
Током layout-а, Flutter преноси ограничења (constraints) одозго наниже кроз RenderObject Tree. Сваки родитељ поставља за објекат детета минималну и максималну ширину и висину. Објекат детета израчунава своју величину у оквиру ових ограничења и враћа је родитељу. Овај процес се назива „downward pass„ (пренос ограничења наниже) и „upward pass„ (пренос димензија навише).
Након завршетка layout-а, Flutter извршава paint — цртање сваког RenderObject-а. Родитељ креира PaintingContext, прослеђује га објектима деце и одређује помак (offset). Сваки RenderObject црта себе на платну Canvas, користећи графичке примитиве: правоугаонике, кругове, текст, слике и трансформације. Canvas директно комуницира са Skia или Impeller.
Flutter користи механизам „прљавих„ чворова за минимизацију посла. Када се промени само величина једног RenderObject-а, Flutter не прерачунава layout целог стабла — означава измењени чвор и његове могуће претке до најближег RenderBox-а са фиксном величином. Слично, при промени изгледа означава се само paint, без понављања layout-а.
Flutter пружа неколико категорија RenderObject-а за различите задатке: RenderBox за стандардне правоугаоне елементе, RenderSliver за области за померање и прилагођени RenderObject за нестандардно рендеровање путем CustomPainter-а. Сваки тип је оптимизован за своју улогу у стаблу рендеровања.
RenderBox — основна класа за правоугаоне елементе интерфејса. Његови подтипови: RenderPadding (додаје размаке), RenderTransform (примењује трансформације), RenderFlex (имплементира Row и Column), RenderStack (преклапање елемената), RenderImage (приказ слика), RenderParagraph (приказ текста). Сваки подтип преписује performLayout и paint за своју логику.
RenderSliver — тип RenderObject-а за рад са областима за померање. За разлику од RenderBox-а, Sliver користи SliverConstraints који укључују информације о видљивој области (viewport). RenderSliverList и RenderSliverGrid креирају RenderObject само за елементе који се налазе у видљивој области, што омогућава обраду листи са милионима записа.
За нестандардну графику користите CustomPaint и CustomPainter. CustomPaint креира RenderCustomPaint који позива методе paint у CustomPainter-у. Ово омогућава цртање произвољних облика, графикона и анимација са потпуном контролом над Canvas-ом. Према Flutter Team, CustomPainter је ефикаснији од угнежђених стандардних виџета за сложену векторску графику.
class CirclePainter extends CustomPainter {
final Color color;
CirclePainter({required this.color});
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()..color = color;
canvas.drawCircle(
Offset(size.width / 2, size.height / 2),
size.width / 3,
paint,
);
}
@override
bool shouldRepaint(CirclePainter oldDelegate) =>
oldDelegate.color != color;
}
У овом примеру, CirclePainter црта круг на Canvas-у. Метод shouldRepaint враћа true само при промени боје, што спречава непотребно прецртавање. CustomPainter треба да буде што лакши — све тешке прорачуне обављајте ван метода paint.
RenderObject Tree се креира из Element Tree кроз механизам RenderObjectWidget. Сваки RenderObjectWidget (Padding, Transform, CustomPaint) креира RenderObjectElement који креира и управља одговарајућим RenderObject-ом. Елемент делује као посредник: преноси конфигурацију са виџета на RenderObject и обавештава RenderObject о променама.
Када се RenderObjectElement монтира, он позива метод createRenderObject свог виџета. Виџет креира инстанцу RenderObject-а и враћа је елементу. Елемент уграђује RenderObject у RenderObject Tree, позивајући метод insertChildLayout код родитељског RenderObject-а. Овај процес се дешава само при првом монтирању — при накнадним ажурирањима елемент једноставно ажурира параметре постојећег RenderObject-а.
Када се конфигурација виџета промени (нпр. промени се вредност padding), елемент позива метод updateRenderObject, који преноси нову конфигурацију постојећем RenderObject-у. RenderObject себе означава као „прљав„ за layout или paint, и при следећем кадру framework врши неопходна ажурирања.
При демонтирању елемента, позива се метод unmount, који уклања RenderObject из RenderObject Tree и ослобађа ресурсе. RenderObject.remove се позива за одвајање од родитеља, након чега објекат може бити сакупљен од стране garbage collector-а. Flutter гарантује да RenderObject не виси у стаблу без одговарајућег елемента.
RepaintBoundary — виџет који креира засебан слој за рендеровање свог садржаја. Када се садржај RepaintBoundary-ја промени, само овај слој се прецртава, а остали делови екрана остају непромењени. RepaintBoundary је посебно користан за анимације, видео плејере, интерактивне графиконе и друге често ажуриране елементе.
У основи RepaintBoundary-ја лежи RenderRepaintBoundary — посебан RenderObject који креира засебан PictureLayer. При првом рендеровању, RenderRepaintBoundary бележи графичке команде у овај слој. При накнадним ажурирањима, ако се променио само садржај унутар RepaintBoundary-ја, Flutter прецртава само овај слој, а не цео екран. Остали слојеви остају непромењени и поново се користе.
Није сваком виџету потребан RepaintBoundary. Користите га када се део интерфејса ажурира високом учесталошћу (60 FPS и више), а остатак екрана је статичан. Типични примери: анимирани индикатор учитавања, видео плејер, игри Canvas, CustomPainter са честим прецртавањем. За статички текст или дугмад, RepaintBoundary је сувишан и само повећава потрошњу меморије.
| Сценарио | Препорука | Разлог |
|---|---|---|
| Анимација | Умотати у RepaintBoundary | Изолује често ажурирану област |
| Листа за померање | Није потребно | ListView аутоматски користи слојеве |
| Статички текст | Није потребно | Нема честих прецртавања |
| CustomPainter | Препоручује се | Често прецртавање графике |
Перформансе RenderObject Tree зависе од броја чворова, дубине стабла и учесталости прецртавања. Алати Flutter DevTools (картица „Rendering„) омогућавају анализу RenderObject Tree у реалном времену: број repaint-ова, време layout-а и paint-а, број слојева и њихове величине. Редовна анализа помаже у идентификацији уских грла.
Overdraw — ситуација када се један пиксел црта више пута по кадру. На пример, када се полупровидни виџет поставља преко другог, GPU црта оба слоја. Користите opaque заставице (Container са color уместо decoration) за непрозирне елементе како би Flutter прескочио невидљиве слојеве. Према Flutter Team, смањење overdraw-а може скратити време paint-а до 30%.
Сваки RepaintBoundary и неки виџети (Opacity, ClipRRect, Transform) креирају засебан слој (PictureLayer). Превише слојева повећава време композиције. Користите груписање: уместо више Opacity на појединачним виџетима, примените један Opacity на контејнеру. Уместо ClipRRect на сваком елементу, користите ClipRRect на заједничком контејнеру.
Када је виџет декларисан као const, Flutter зна да се његова конфигурација неће променити и може поново користити одговарајући RenderObject без поновног креирања. Const-конструктори смањују оптерећење garbage collector-а и убрзавају први кадар. Користите const за виџете са фиксним параметрима: иконе, наслове, декоративне елементе.
const Text("Наслов", style: TextStyle(fontSize: 24));
const Icon(Icons.home, color: Colors.blue);
const SizedBox.shrink();
Често постављана питања
Widget Tree — лака конфигурација интерфејса која се поново креира при сваком rebuild-у. RenderObject Tree — тешко стабло објеката за рендеровање које се чува и ажурира само при промени геометрије или изгледа.
Користите Flutter DevTools — картица „Rendering„. Видећете слојеве рендеровања, време layout-а и paint-а, као и детаљне информације о сваком RenderObject-у: димензије, constraints, заставице потребе за ажурирањем.
Dirty — RenderObject који је означен као да захтева ажурирање. Заставица _needsLayout или _needsPaint се поставља при промени конфигурације, и Flutter извршава layout или paint за овај чвор у следећем кадру.
Да, креирајте подкласу RenderBox и препишите методе performLayout и paint. Користите RenderObjectWidget за уграђивање прилагођеног RenderObject-а у Widget Tree. Ово је напредна техника за нестандардно рендеровање.
RepaintBoundary креира RenderRepaintBoundary који изолује део RenderObject Tree у засебан слој. При промени садржаја, само овај слој се прецртава, а остатак стабла остаје непромењен.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође