RenderObject Tree: cos'è, principi di rendering e ruolo in Flutter

Autore: IT Sectr Pubblicato: 2026-07-01 Tempo di lettura: 9 min

RenderObject Tree è il terzo livello della gerarchia di Flutter, responsabile del rendering effettivo dell'interfaccia sullo schermo. Ogni nodo di questo albero esegue il calcolo delle dimensioni (layout) e il disegno (painting), convertendo la configurazione dei widget in pixel. A differenza del Widget Tree, il RenderObject Tree viene creato una volta e aggiornato solo quando cambiano la geometria o l'aspetto. Secondo il Riferimento API Flutter, 2025, l'efficienza del RenderObject Tree determina direttamente la fluidità delle animazioni e la reattività dell'applicazione.

Punti chiave

  • RenderObject Tree è una gerarchia di oggetti di rendering che calcolano le dimensioni e disegnano l'interfaccia sullo schermo.
  • Ogni RenderObject esegue due fasi: layout (determinazione di dimensioni e posizioni) e paint (disegno dei pixel).
  • RenderObject Tree viene creato dall'Element Tree e sincronizzato con esso tramite gli elementi.
  • RepaintBoundary isola una parte dell'albero per il ripainting locale senza influenzare l'intero schermo.
  • Le prestazioni del RenderObject Tree dipendono dalla profondità, dal numero di layer e dalla frequenza di ripainting.

Cos'è il RenderObject Tree in Flutter?

RenderObject Tree è una struttura gerarchica di oggetti di rendering che funge da rappresentazione effettiva dell'interfaccia in memoria. Ogni RenderObject conosce le proprie dimensioni, la posizione sullo schermo e come disegnarsi. A differenza dei widget, che sono leggeri e possono essere ricreati centinaia di volte al secondo, un RenderObject è un oggetto pesante con accesso diretto alla pipeline grafica.

Dalla configurazione al rendering

Il percorso dal widget ai pixel passa attraverso tre fasi: il Widget Tree descrive ciò che deve essere sullo schermo; l'Element Tree gestisce il ciclo di vita; il RenderObject Tree esegue il lavoro effettivo. Ogni RenderObjectWidget (come Padding, Transform, CustomPaint) crea un RenderObject che viene aggiunto all'albero di rendering. RenderBox è il tipo più comune di RenderObject, utilizzato dal 99% dei widget standard.

Architettura di RenderObject

RenderObject è una classe astratta che definisce l'interfaccia per layout e paint. Contiene riferimenti al RenderObject padre e agli oggetti figli, nonché metodi astratti: performLayout, paint e hitTest. Ogni RenderObject concreto implementa questi metodi secondo il proprio comportamento: RenderFlex distribuisce lo spazio tra i figli, RenderImage visualizza un'immagine, RenderParagraph rende il testo.

dart
abstract class RenderObject {
  RenderObject? parent;
  Constraints constraints;
  ParentData? parentData;
  bool _needsLayout = true;
  bool _needsPaint = true;

  void performLayout();
  void paint(PaintingContext context, Offset offset);
}

In questa struttura semplificata, RenderObject contiene i flag _needsLayout e _needsPaint, che marcano l'oggetto come bisognoso di aggiornamento. Quando il Widget Tree cambia, l'Element Tree marca i RenderObject corrispondenti come "sporchi" per layout o paint, e al frame successivo Flutter esegue solo le operazioni necessarie.

Le due fasi di RenderObject: layout e paint

Ogni RenderObject esegue due fasi principali: layout (determinazione di dimensioni e posizioni) e paint (disegno). Queste fasi vengono eseguite in ordine rigoroso: prima layout per l'intero albero, poi paint. La fase di paint può essere saltata se il layout non è cambiato, risparmiando risorse della GPU.

Fase di layout: vincoli e dimensioni

Durante il layout, Flutter passa vincoli (constraints) dall'alto verso il basso attraverso il RenderObject Tree. Ogni genitore definisce larghezza e altezza minima e massima per il proprio figlio. Il figlio calcola le proprie dimensioni all'interno di questi vincoli e le restituisce al genitore. Questo processo è chiamato "downward pass" (passaggio dei vincoli verso il basso) e "upward pass" (passaggio delle dimensioni verso l'alto).

  • BoxConstraints è il tipo di vincolo più comune: minWidth, maxWidth, minHeight, maxHeight.
  • SliverConstraints viene utilizzato in ScrollView per la virtualizzazione: aggiunge informazioni di scorrimento ai vincoli standard.
  • RenderSliverMultiBoxAdaptor gestisce il layout di liste virtualizzate, creando RenderObject solo per gli elementi visibili.

Fase di paint: visualizzazione sullo schermo

Dopo aver completato il layout, Flutter esegue il paint — disegno di ogni RenderObject. Il genitore crea un PaintingContext, lo passa agli oggetti figli e specifica l'offset. Ogni RenderObject si disegna sulla Canvas utilizzando primitive grafiche: rettangoli, cerchi, testo, immagini e trasformazioni. La Canvas interagisce direttamente con Skia o Impeller.

Marcatura dei nodi sporchi

Flutter utilizza un meccanismo di nodi "sporchi" per minimizzare il lavoro. Quando solo la dimensione di un RenderObject cambia, Flutter non ricalcola il layout dell'intero albero — marca il nodo modificato e i suoi possibili antenati fino al RenderBox più vicino con dimensione fissa. Analogamente, quando l'aspetto cambia, viene marcato solo paint senza rifare il layout.

Tipi di RenderObject in Flutter

Flutter fornisce diverse categorie di RenderObject per compiti differenti: RenderBox per elementi rettangolari standard, RenderSliver per aree scorrevoli e RenderObject personalizzati per rendering non standard tramite CustomPainter. Ogni tipo è ottimizzato per il proprio ruolo nell'albero di rendering.

RenderBox e i suoi sottotipi

RenderBox è la classe base per gli elementi di interfaccia rettangolari. I suoi sottotipi includono: RenderPadding (aggiunge padding), RenderTransform (applica trasformazioni), RenderFlex (implementa Row e Column), RenderStack (sovrappone elementi), RenderImage (visualizza immagini), RenderParagraph (rende il testo). Ogni sottotipo sovrascrive performLayout e paint per la propria logica.

RenderSliver e virtualizzazione

RenderSliver è un tipo di RenderObject per lavorare con aree scorrevoli. A differenza di RenderBox, Sliver utilizza SliverConstraints, che includono informazioni sul viewport. RenderSliverList e RenderSliverGrid creano RenderObject solo per gli elementi nell'area visibile, consentendo di gestire elenchi con milioni di voci.

RenderObject personalizzato tramite CustomPainter

Per grafiche non standard, utilizzare CustomPaint e CustomPainter. CustomPaint crea RenderCustomPaint, che chiama i metodi paint di CustomPainter. Ciò consente di disegnare forme arbitrarie, grafici e animazioni con controllo completo sulla Canvas. Secondo il team di Flutter, CustomPainter è più efficiente dei widget standard annidati per la grafica vettoriale complessa.

dart
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;
}

In questo esempio, CirclePainter disegna un cerchio sulla Canvas. Il metodo shouldRepaint restituisce true solo quando il colore cambia, prevenendo ripainting non necessari. CustomPainter dovrebbe essere il più leggero possibile — esegui tutti i calcoli pesanti al di fuori dei metodi paint.

RenderObject Tree viene creato dall'Element Tree attraverso il meccanismo RenderObjectWidget. Ogni RenderObjectWidget (Padding, Transform, CustomPaint) crea un RenderObjectElement, che a sua volta crea e gestisce il RenderObject corrispondente. L'elemento funge da intermediario: passa la configurazione dal widget al RenderObject e notifica il RenderObject dei cambiamenti.

Creazione di un RenderObject da un elemento

Quando un RenderObjectElement viene montato, chiama il metodo createRenderObject sul suo widget. Il widget crea un'istanza di RenderObject e la restituisce all'elemento. L'elemento inserisce il RenderObject nel RenderObject Tree chiamando il metodo insertChildLayout sul RenderObject padre. Questo processo avviene solo al primo montaggio — negli aggiornamenti successivi, l'elemento aggiorna semplicemente i parametri del RenderObject esistente.

Sincronizzazione tramite updateRenderObject

Quando la configurazione del widget cambia (ad esempio, il valore di padding cambia), l'elemento chiama il metodo updateRenderObject, che passa la nuova configurazione al RenderObject esistente. Il RenderObject si marca come "sporco" per layout o paint, e al frame successivo il framework esegue gli aggiornamenti necessari.

Rimozione di un RenderObject

Quando un elemento viene smontato, viene chiamato il metodo unmount, che rimuove il RenderObject dal RenderObject Tree e libera le risorse. RenderObject.remove viene chiamato per scollegarsi dal genitore, dopodiché l'oggetto può essere raccolto dal garbage collector. Flutter garantisce che nessun RenderObject rimanga sospeso nell'albero senza un elemento corrispondente.

RepaintBoundary e isolamento del rendering

RepaintBoundary è un widget che crea un layer separato per il rendering del suo contenuto. Quando il contenuto all'interno di un RepaintBoundary cambia, solo quel layer viene ripainted, mentre il resto dello schermo rimane invariato. RepaintBoundary è particolarmente utile per animazioni, lettori video, grafici interattivi e altri elementi aggiornati frequentemente.

Come funziona RepaintBoundary

Al centro di RepaintBoundary c'è RenderRepaintBoundary — un RenderObject speciale che crea un PictureLayer separato. Al primo rendering, RenderRepaintBoundary registra i comandi grafici in questo layer. Negli aggiornamenti successivi, se solo il contenuto all'interno del RepaintBoundary cambia, Flutter ripaints solo questo layer anziché l'intero schermo. Gli altri layer rimangono invariati e vengono riutilizzati.

Quando usare RepaintBoundary

Non tutti i widget hanno bisogno di RepaintBoundary. Usalo quando una parte dell'interfaccia si aggiorna ad alta frequenza (60 FPS o superiore) mentre il resto dello schermo è statico. Esempi tipici: un indicatore di caricamento animato, lettore video, Canvas di gioco, CustomPainter con ripainting frequenti. Per testo statico o pulsanti, RepaintBoundary è eccessivo e aumenta solo il consumo di memoria.

ScenarioRaccomandazioneMotivo
AnimazioneAvvolgere in RepaintBoundaryIsola l'area aggiornata frequentemente
Elenco scorrevoleNon necessarioListView usa i layer automaticamente
Testo staticoNon necessarioNessun ripainting frequente
CustomPainterRaccomandatoRipainting grafico frequente

Ottimizzazione del RenderObject Tree per le prestazioni

Le prestazioni del RenderObject Tree dipendono dal numero di nodi, dalla profondità dell'albero e dalla frequenza di ripainting. Flutter DevTools (la scheda "Rendering") consente di analizzare il RenderObject Tree in tempo reale: conteggio dei ripaint, tempo di layout e paint, numero di layer e loro dimensioni. L'analisi regolare aiuta a identificare i colli di bottiglia.

Evita l'overdraw eccessivo

Overdraw è una situazione in cui un singolo pixel viene disegnato più volte per frame. Ad esempio, quando un widget semitrasparente si sovrappone a un altro, la GPU disegna entrambi i layer. Utilizza flag opachi (Container con color invece di decoration) per elementi non trasparenti, in modo che Flutter salti i layer invisibili. Secondo il team di Flutter, ridurre l'overdraw può diminuire il tempo di paint fino al 30%.

Minimizza il numero di layer

Ogni RepaintBoundary e alcuni widget (Opacity, ClipRRect, Transform) creano un layer separato (PictureLayer). Troppi layer aumentano il tempo di composizione. Utilizza il raggruppamento: invece di più widget Opacity su singoli elementi, applica una singola Opacity al contenitore. Invece di ClipRRect su ogni elemento, usa ClipRRect sul contenitore comune.

Usa costruttori const

Quando un widget viene dichiarato come const, Flutter sa che la sua configurazione non cambierà e può riutilizzare il RenderObject corrispondente senza ricrearlo. I costruttori const riducono il carico del garbage collector e accelerano il primo frame. Usa const per widget con parametri fissi: icone, titoli, elementi decorativi.

dart
const Text("Titolo", style: TextStyle(fontSize: 24));
const Icon(Icons.home, color: Colors.blue);
const SizedBox.shrink();

Domande frequenti

In cosa si differenzia il RenderObject Tree dal Widget Tree?

Widget Tree è una configurazione leggera dell'interfaccia che viene ricreata ad ogni ricostruzione. RenderObject Tree è un albero pesante di oggetti di rendering che persiste e viene aggiornato solo quando cambiano geometria o aspetto.

Come posso vedere il RenderObject Tree nel debugger?

Usa Flutter DevTools — la scheda "Rendering". Vedrai i layer di rendering, i tempi di layout e paint, e informazioni dettagliate su ogni RenderObject: dimensioni, vincoli e flag sporchi.

Cos'è un RenderObject sporco?

Dirty è un RenderObject marcato come bisognoso di aggiornamento. Il flag _needsLayout o _needsPaint viene impostato quando la configurazione cambia, e Flutter esegue layout o paint per quel nodo al frame successivo.

Posso creare il mio RenderObject personalizzato?

Sì, crea una sottoclasse di RenderBox e sovrascrivi i metodi performLayout e paint. Usa RenderObjectWidget per incorporare un RenderObject personalizzato nel Widget Tree. Questa è una tecnica avanzata per rendering non standard.

Come RepaintBoundary influisce sul RenderObject Tree?

RepaintBoundary crea RenderRepaintBoundary, che isola una parte del RenderObject Tree in un layer separato. Quando il contenuto cambia, solo quel layer viene ripainted, lasciando inalterato il resto dell'albero.

Riepilogo

  • RenderObject Tree è il terzo livello dell'architettura di Flutter, responsabile del layout e paint di ogni elemento dell'interfaccia.
  • Ogni RenderObject esegue due fasi: layout (calcolo di dimensioni e posizioni) e paint (disegno dei pixel tramite Canvas).
  • RenderBox è il tipo base per elementi standard, RenderSliver per virtualizzare elenchi scorrevoli.
  • RenderObject Tree è sincronizzato con l'Element Tree tramite RenderObjectElement, che crea e aggiorna i RenderObject.
  • RepaintBoundary isola una parte dell'albero in un layer separato, prevenendo il ripainting completo dello schermo in caso di modifiche locali.
  • Le prestazioni dipendono dalla profondità dell'albero, dal numero di layer, dall'overdraw e dall'uso di costruttori const.
  • Flutter DevTools fornisce strumenti per analizzare il RenderObject Tree: tempo di layout, tempo di paint, numero di layer e ripaint.

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche