RenderObject Tree — este al treilea nivel al ierarhiei în Flutter, responsabil pentru randarea efectivă a interfeței pe ecran. Fiecare nod al acestui arbore efectuează calcularea dimensiunilor (layout) și desenarea (painting), transformând configurația widgeturilor în pixeli. Spre deosebire de Widget Tree, RenderObject Tree este creat o singură dată și actualizat doar la modificarea geometriei sau aspectului. Conform Flutter API Reference, 2025, eficiența RenderObject Tree determină direct netezimea animațiilor și viteza de răspuns a aplicației.
Puncte principale
RenderObject Tree — este o structură ierarhică de obiecte de randare care reprezintă efectiv interfața în memorie. Fiecare RenderObject își cunoaște dimensiunile, poziția pe ecran și știe să se deseneze. Spre deosebire de widgeturi, care sunt ușoare și pot fi recreate de sute de ori pe secundă, RenderObject — este un obiect greu cu acces direct la conducta grafică.
Drumul de la widget la pixeli parcurge trei etape: Widget Tree descrie ce ar trebui să fie pe ecran; Element Tree gestionează ciclul de viață; RenderObject Tree efectuează munca reală. Fiecare RenderObjectWidget (de exemplu, Padding, Transform, CustomPaint) creează un RenderObject care este adăugat în arborele de randare. RenderBox — cel mai răspândit tip de RenderObject, folosit pentru 99% din widgeturile standard.
RenderObject — este o clasă abstractă care definește interfața pentru layout și paint. Conține referințe către RenderObject părinte și obiecte copil, precum și metode abstracte: performLayout, paint și hitTest. Fiecare RenderObject concret implementează aceste metode conform comportamentului său: RenderFlex distribuie spațiul între elementele copil, RenderImage afișează imaginea, RenderParagraph afișează textul.
abstract class RenderObject {
RenderObject? parent;
Constraints constraints;
ParentData? parentData;
bool _needsLayout = true;
bool _needsPaint = true;
void performLayout();
void paint(PaintingContext context, Offset offset);
}
În această structură simplificată, RenderObject conține flagurile _needsLayout și _needsPaint care marchează obiectul ca necesitând actualizare. Când Widget Tree se modifică, Element Tree marchează RenderObject-urile corespunzătoare ca „murdare„ pentru layout sau paint, iar la următorul cadru Flutter execută doar operațiile necesare.
Fiecare RenderObject execută două faze cheie: layout (determinarea dimensiunilor și pozițiilor) și paint (desenarea). Aceste faze se execută în ordine strictă: mai întâi layout pentru întregul arbore, apoi paint. Faza paint poate fi omisă dacă layout nu s-a modificat, ceea ce economisește resursele GPU.
În timpul layout, Flutter transmite constrângeri (constraints) de sus în jos prin RenderObject Tree. Fiecare părinte stabilește pentru obiectul copil lățimea și înălțimea minimă și maximă. Obiectul copil își calculează dimensiunea în cadrul acestor constrângeri și o returnează părintelui. Acest proces se numește „downward pass„ (transmiterea constrângerilor în jos) și „upward pass„ (transmiterea dimensiunilor în sus).
După finalizarea layout, Flutter execută paint — desenarea fiecărui RenderObject. Părintele creează un PaintingContext, îl transmite obiectelor copil și specifică deplasarea (offset). Fiecare RenderObject se desenează pe Canvas folosind primitive grafice: dreptunghiuri, cercuri, text, imagini și transformări. Canvas interacționează direct cu Skia sau Impeller.
Flutter folosește mecanismul nodurilor „murdare„ pentru a minimiza munca. Când se modifică doar dimensiunea unui RenderObject, Flutter nu recalculează layout-ul întregului arbore — marchează nodul modificat și posibilii săi strămoși până la cel mai apropiat RenderBox cu dimensiune fixă. Similar, la modificarea aspectului, se marchează doar paint, fără a repeta layout-ul.
Flutter oferă mai multe categorii de RenderObject pentru diferite sarcini: RenderBox pentru elementele dreptunghiulare standard, RenderSliver pentru zonele derulabile și RenderObject personalizat pentru randarea nestandard prin CustomPainter. Fiecare tip este optimizat pentru rolul său în arborele de randare.
RenderBox — clasa de bază pentru elementele de interfață dreptunghiulare. Subtipurile sale: RenderPadding (adaugă spațiere), RenderTransform (aplică transformări), RenderFlex (implementează Row și Column), RenderStack (suprapunerea elementelor), RenderImage (afișarea imaginilor), RenderParagraph (afișarea textului). Fiecare subtip suprascrie performLayout și paint pentru logica sa.
RenderSliver — este un tip de RenderObject pentru lucrul cu zonele derulabile. Spre deosebire de RenderBox, Sliver folosește SliverConstraints care includ informații despre zona vizibilă (viewport). RenderSliverList și RenderSliverGrid creează RenderObject doar pentru elementele care se află în zona vizibilă, permițând procesarea listelor cu milioane de înregistrări.
Pentru grafică nestandard, utilizați CustomPaint și CustomPainter. CustomPaint creează RenderCustomPaint care apelează metodele paint din CustomPainter. Acest lucru permite desenarea de forme arbitrare, grafice și animații cu control complet asupra Canvas. Conform Flutter Team, CustomPainter este mai eficient decât widgeturile standard imbricate pentru grafica vectorială complexă.
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;
}
În acest exemplu, CirclePainter desenează un cerc pe Canvas. Metoda shouldRepaint returnează true doar la schimbarea culorii, prevenind redesenarea inutilă. CustomPainter trebuie să fie cât mai ușor — toate calculele grele le efectuați în afara metodelor paint.
RenderObject Tree este creat din Element Tree prin mecanismul RenderObjectWidget. Fiecare RenderObjectWidget (Padding, Transform, CustomPaint) creează un RenderObjectElement care creează și gestionează RenderObject-ul corespunzător. Elementul acționează ca intermediar: transmite configurația de la widget la RenderObject și notifică RenderObject-ul despre modificări.
Când RenderObjectElement este montat, acesta apelează metoda createRenderObject a widgetului său. Widgetul creează o instanță a RenderObject și o returnează elementului. Elementul încorporează RenderObject în RenderObject Tree, apelând metoda insertChildLayout la RenderObject-ul părinte. Acest proces are loc doar la prima montare — la actualizările ulterioare, elementul pur și simplu actualizează parametrii RenderObject-ului existent.
Când configurația widgetului se modifică (de exemplu, se schimbă valoarea padding), elementul apelează metoda updateRenderObject, care transmite noua configurație RenderObject-ului existent. RenderObject se marchează ca „murdar„ pentru layout sau paint, iar la următorul cadru framework-ul efectuează actualizările necesare.
La demontarea elementului, se apelează metoda unmount, care elimină RenderObject din RenderObject Tree și eliberează resursele. RenderObject.remove este apelat pentru deconectarea de la părinte, după care obiectul poate fi colectat de garbage collector. Flutter garantează că RenderObject nu rămâne în arbore fără elementul corespunzător.
RepaintBoundary — este un widget care creează un strat separat pentru randarea conținutului său. Când conținutul RepaintBoundary se modifică, doar acest strat este redesenat, iar restul părților ecranului rămân neschimbate. RepaintBoundary este deosebit de util pentru animații, playere video, grafice interactive și alte elemente actualizate frecvent.
La baza RepaintBoundary stă RenderRepaintBoundary — un RenderObject special care creează un PictureLayer separat. La prima randare, RenderRepaintBoundary înregistrează comenzile grafice în acest strat. La actualizările ulterioare, dacă doar conținutul din interiorul RepaintBoundary s-a modificat, Flutter redesenează doar acest strat, nu întregul ecran. Celelalte straturi rămân neschimbate și sunt reutilizate.
Nu orice widget are nevoie de RepaintBoundary. Folosiți-l când o parte a interfeței se actualizează cu frecvență ridicată (60 FPS și mai mult), iar restul ecranului este static. Exemple tipice: indicator de încărcare animat, player video, Canvas de joc, CustomPainter cu redesenare frecventă. Pentru text static sau butoane, RepaintBoundary este redundant și doar crește consumul de memorie.
| Scenariu | Recomandare | Motiv |
|---|---|---|
| Animație | Înveliți în RepaintBoundary | Izolează zona actualizată frecvent |
| Listă derulabilă | Nu este necesar | ListView folosește straturi automat |
| Text static | Nu este necesar | Nu are redesenări frecvente |
| CustomPainter | Recomandat | Redesenare frecventă a graficii |
Performanța RenderObject Tree depinde de numărul de noduri, adâncimea arborelui și frecvența redesenărilor. Instrumentele Flutter DevTools (filia „Rendering„) permit analizarea RenderObject Tree în timp real: numărul de repaint, timpul de layout și paint, numărul de straturi și dimensiunile lor. Analiza regulată ajută la identificarea blocajelor.
Overdraw — este situația în care un pixel este desenat de mai multe ori pe cadru. De exemplu, când un widget semitransparent se suprapune peste altul, GPU desenează ambele straturi. Utilizați flaguri opaque (Container cu color în loc de decoration) pentru elementele opace, pentru ca Flutter să sară peste straturile invizibile. Conform Flutter Team, reducerea overdraw-ului poate scurta timpul de paint cu până la 30%.
Fiecare RepaintBoundary și unele widgeturi (Opacity, ClipRRect, Transform) creează un strat separat (PictureLayer). Prea multe straturi măresc timpul de compoziție. Utilizați gruparea: în loc de mai multe Opacity pe widgeturi separate, aplicați un singur Opacity pe container. În loc de ClipRRect pe fiecare element, utilizați ClipRRect pe containerul comun.
Când un widget este declarat ca const, Flutter știe că configurația sa nu se va modifica și poate reutiliza RenderObject-ul corespunzător fără recreere. Constructorii const reduc încărcarea garbage collector-ului și accelerează primul cadru. Utilizați const pentru widgeturi cu parametri fixi: pictograme, titluri, elemente decorative.
const Text("Titlu", style: TextStyle(fontSize: 24));
const Icon(Icons.home, color: Colors.blue);
const SizedBox.shrink();
Întrebări frecvente
Widget Tree — este o configurație ușoară a interfeței care este recreată la fiecare rebuild. RenderObject Tree — este un arbore greu de obiecte de randare care se păstrează și se actualizează doar la modificarea geometriei sau aspectului.
Folosiți Flutter DevTools — filia „Rendering„. Veți vedea straturile de randare, timpul de layout și paint, precum și informații detaliate despre fiecare RenderObject: dimensiuni, constraints, flaguri de necesitate a actualizării.
Dirty — este un RenderObject marcat ca necesitând actualizare. Flagul _needsLayout sau _needsPaint este setat la modificarea configurației, iar Flutter execută layout sau paint pentru acest nod în următorul cadru.
Da, creați o subclasă a RenderBox și suprascrieți metodele performLayout și paint. Utilizați RenderObjectWidget pentru încorporarea RenderObject-ului personalizat în Widget Tree. Aceasta este o tehnică avansată pentru randare nestandard.
RepaintBoundary creează RenderRepaintBoundary care izolează o parte a RenderObject Tree într-un strat separat. La modificarea conținutului, doar acest strat este redesenat, iar restul arborelui rămâne neschimbat.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și