RenderObject Tree : définition, principes de rendu et rôle dans Flutter

Auteur : IT Sectr Publié le : 2026-07-01 Temps de lecture : 9 min

RenderObject Tree est le troisième niveau de la hiérarchie Flutter, responsable du rendu effectif de l’interface à l’écran. Chaque nœud de cet arbre effectue le calcul des tailles (layout) et le dessin (painting), convertissant la configuration des widgets en pixels. Contrairement au Widget Tree, le RenderObject Tree est créé une seule fois et mis à jour uniquement en cas de modification de la géométrie ou de l’apparence. Selon la Référence API Flutter, 2025, l’efficacité du RenderObject Tree détermine directement la fluidité des animations et la réactivité de l’application.

Points clés

  • RenderObject Tree est une hiérarchie d’objets de rendu qui calculent les tailles et dessinent l’interface à l’écran.
  • Chaque RenderObject effectue deux phases : layout (détermination des tailles et positions) et paint (dessin des pixels).
  • RenderObject Tree est créé à partir de l’Element Tree et synchronisé avec lui via les éléments.
  • RepaintBoundary isole une partie de l’arbre pour un repeint local sans affecter tout l’écran.
  • Les performances du RenderObject Tree dépendent de la profondeur, du nombre de couches et de la fréquence de repeint.

Qu’est-ce que le RenderObject Tree dans Flutter ?

RenderObject Tree est une structure hiérarchique d’objets de rendu qui sert de représentation réelle de l’interface en mémoire. Chaque RenderObject connaît sa propre taille, sa position à l’écran et comment se dessiner. Contrairement aux widgets, qui sont légers et peuvent être recréés des centaines de fois par seconde, un RenderObject est un objet lourd avec un accès direct au pipeline graphique.

De la configuration au rendu

Le chemin du widget aux pixels passe par trois étapes : le Widget Tree décrit ce qui doit être à l’écran ; l’Element Tree gère le cycle de vie ; le RenderObject Tree effectue le travail réel. Chaque RenderObjectWidget (comme Padding, Transform, CustomPaint) crée un RenderObject qui est ajouté à l’arbre de rendu. RenderBox est le type de RenderObject le plus courant, utilisé pour 99 % des widgets standard.

Architecture de RenderObject

RenderObject est une classe abstraite qui définit l’interface pour le layout et le paint. Elle contient des références au RenderObject parent et aux objets enfants, ainsi que des méthodes abstraites : performLayout, paint et hitTest. Chaque RenderObject concret implémente ces méthodes selon son comportement : RenderFlex répartit l’espace entre les enfants, RenderImage affiche une image, RenderParagraph restitue du texte.

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

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

Dans cette structure simplifiée, RenderObject contient les indicateurs _needsLayout et _needsPaint, qui marquent l’objet comme nécessitant une mise à jour. Lorsque le Widget Tree change, l’Element Tree marque les RenderObjects correspondants comme « sales » pour le layout ou le paint, et à l’image suivante, Flutter effectue uniquement les opérations nécessaires.

Les deux phases de RenderObject : layout et paint

Chaque RenderObject effectue deux phases principales : layout (détermination des tailles et positions) et paint (dessin). Ces phases sont exécutées dans un ordre strict : d’abord le layout pour tout l’arbre, puis le paint. La phase de paint peut être sautée si le layout n’a pas changé, ce qui économise les ressources du GPU.

Phase de layout : contraintes et tailles

Pendant le layout, Flutter transmet les contraintes (constraints) de haut en bas à travers le RenderObject Tree. Chaque parent définit une largeur et une hauteur minimale et maximale pour son enfant. L’enfant calcule sa taille dans ces contraintes et la retourne au parent. Ce processus est appelé « passage descendant » (transmission des contraintes vers le bas) et « passage ascendant » (transmission des tailles vers le haut).

  • BoxConstraints est le type de contrainte le plus courant : minWidth, maxWidth, minHeight, maxHeight.
  • SliverConstraints est utilisé dans ScrollView pour la virtualisation : il ajoute des informations de défilement aux contraintes standard.
  • RenderSliverMultiBoxAdaptor gère le layout des listes virtualisées, en créant des RenderObjects uniquement pour les éléments visibles.

Phase de paint : affichage à l’écran

Après avoir terminé le layout, Flutter effectue le paint — le dessin de chaque RenderObject. Le parent crée un PaintingContext, le transmet aux objets enfants et spécifie le décalage (offset). Chaque RenderObject se dessine sur le Canvas en utilisant des primitives graphiques : rectangles, cercles, texte, images et transformations. Le Canvas interagit directement avec Skia ou Impeller.

Marquage des nœuds sales

Flutter utilise un mécanisme de nœuds « sales » pour minimiser le travail. Lorsque seule la taille d’un RenderObject change, Flutter ne recalcule pas le layout de tout l’arbre — il marque le nœud modifié et ses ancêtres possibles jusqu’au RenderBox le plus proche avec une taille fixe. De même, lorsque l’apparence change, seul le paint est marqué sans refaire le layout.

Types de RenderObject dans Flutter

Flutter propose plusieurs catégories de RenderObject pour différentes tâches : RenderBox pour les éléments rectangulaires standard, RenderSliver pour les zones défilables et des RenderObjects personnalisés pour le rendu non standard via CustomPainter. Chaque type est optimisé pour son rôle dans l’arbre de rendu.

RenderBox et ses sous-types

RenderBox est la classe de base pour les éléments d’interface rectangulaires. Ses sous-types incluent : RenderPadding (ajoute du remplissage), RenderTransform (applique des transformations), RenderFlex (implémente Row et Column), RenderStack (superpose des éléments), RenderImage (affiche des images), RenderParagraph (rend du texte). Chaque sous-type redéfinit performLayout et paint pour sa propre logique.

RenderSliver et virtualisation

RenderSliver est un type de RenderObject pour travailler avec des zones défilables. Contrairement à RenderBox, Sliver utilise SliverConstraints, qui incluent des informations sur la zone d’affichage (viewport). RenderSliverList et RenderSliverGrid créent des RenderObjects uniquement pour les éléments dans la zone visible, permettant de gérer des listes contenant des millions d’entrées.

RenderObject personnalisé via CustomPainter

Pour les graphismes non standard, utilisez CustomPaint et CustomPainter. CustomPaint crée RenderCustomPaint, qui appelle les méthodes paint de CustomPainter. Cela permet de dessiner des formes arbitraires, des graphiques et des animations avec un contrôle total sur le Canvas. Selon l’équipe Flutter, CustomPainter est plus efficace que les widgets standard imbriqués pour les graphiques vectoriels complexes.

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

Dans cet exemple, CirclePainter dessine un cercle sur le Canvas. La méthode shouldRepaint ne retourne true que lorsque la couleur change, ce qui évite les repeints inutiles. CustomPainter doit être aussi léger que possible — effectuez tous les calculs lourds en dehors des méthodes paint.

RenderObject Tree est créé à partir de l’Element Tree via le mécanisme RenderObjectWidget. Chaque RenderObjectWidget (Padding, Transform, CustomPaint) crée un RenderObjectElement, qui à son tour crée et gère le RenderObject correspondant. L’élément agit comme un intermédiaire : il transmet la configuration du widget au RenderObject et notifie le RenderObject des changements.

Création d’un RenderObject à partir d’un élément

Lorsqu’un RenderObjectElement est monté, il appelle la méthode createRenderObject de son widget. Le widget crée une instance de RenderObject et la retourne à l’élément. L’élément insère le RenderObject dans le RenderObject Tree en appelant la méthode insertChildLayout du RenderObject parent. Ce processus ne se produit que lors du premier montage — lors des mises à jour suivantes, l’élément met simplement à jour les paramètres du RenderObject existant.

Synchronisation via updateRenderObject

Lorsque la configuration du widget change (par exemple, la valeur de padding change), l’élément appelle la méthode updateRenderObject, qui transmet la nouvelle configuration au RenderObject existant. Le RenderObject se marque comme « sale » pour le layout ou le paint, et à l’image suivante, le framework effectue les mises à jour nécessaires.

Suppression d’un RenderObject

Lorsqu’un élément est démonté, la méthode unmount est appelée, ce qui supprime le RenderObject du RenderObject Tree et libère les ressources. RenderObject.remove est appelé pour se détacher du parent, après quoi l’objet peut être récupéré par le ramasse-miettes. Flutter garantit qu’aucun RenderObject ne reste accroché dans l’arbre sans élément correspondant.

RepaintBoundary et l’isolation du rendu

RepaintBoundary est un widget qui crée une couche séparée pour le rendu de son contenu. Lorsque le contenu d’un RepaintBoundary change, seule cette couche est repeinte, tandis que le reste de l’écran reste inchangé. RepaintBoundary est particulièrement utile pour les animations, les lecteurs vidéo, les graphiques interactifs et autres éléments fréquemment mis à jour.

Comment fonctionne RepaintBoundary

Au cœur de RepaintBoundary se trouve RenderRepaintBoundary — un RenderObject spécial qui crée un PictureLayer séparé. Lors du premier rendu, RenderRepaintBoundary enregistre les commandes graphiques dans cette couche. Lors des mises à jour ultérieures, si seul le contenu à l’intérieur du RepaintBoundary change, Flutter repeint uniquement cette couche au lieu de tout l’écran. Les autres couches restent inchangées et sont réutilisées.

Quand utiliser RepaintBoundary

Tous les widgets n’ont pas besoin de RepaintBoundary. Utilisez-le lorsqu’une partie de l’interface se met à jour à haute fréquence (60 FPS ou plus) tandis que le reste de l’écran est statique. Exemples typiques : un indicateur de chargement animé, un lecteur vidéo, un Canvas de jeu, un CustomPainter avec des repeints fréquents. Pour du texte statique ou des boutons, RepaintBoundary est excessif et ne fait qu’augmenter la consommation de mémoire.

ScénarioRecommandationRaison
AnimationEnvelopper dans RepaintBoundaryIsole la zone fréquemment mise à jour
Liste dŸilablePas nécessaireListView utilise les couches automatiquement
Texte statiquePas nécessairePas de repeints fréquents
CustomPainterRecommandéRepeints graphiques fréquents

Optimisation du RenderObject Tree pour les performances

Les performances du RenderObject Tree dépendent du nombre de nœuds, de la profondeur de l’arbre et de la fréquence de repeint. Flutter DevTools (l’onglet « Rendering ») permet d’analyser le RenderObject Tree en temps réel : nombre de repeints, temps de layout et de paint, nombre de couches et leurs tailles. Une analyse régulière permet d’identifier les goulots d’étranglement.

Évitez le overdraw excessif

Overdraw est une situation où un même pixel est dessiné plusieurs fois par image. Par exemple, lorsqu’un widget semi-transparent chevauche un autre, le GPU dessine les deux couches. Utilisez des indicateurs opaques (Container avec color au lieu de decoration) pour les éléments non transparents, afin que Flutter ignore les couches invisibles. Selon l’équipe Flutter, la réduction du overdraw peut diminuer le temps de paint jusqu’à 30 %.

Minimisez le nombre de couches

Chaque RepaintBoundary et certains widgets (Opacity, ClipRRect, Transform) créent une couche séparée (PictureLayer). Trop de couches augmentent le temps de composition. Utilisez le regroupement : au lieu de plusieurs widgets Opacity sur des éléments individuels, appliquez une seule Opacity au conteneur. Au lieu de ClipRRect sur chaque élément, utilisez ClipRRect sur le conteneur commun.

Utilisez les constructeurs const

Lorsqu’un widget est déclaré comme const, Flutter sait que sa configuration ne changera pas et peut réutiliser le RenderObject correspondant sans le recréer. Les constructeurs const réduisent la charge du ramasse-miettes et accélèrent la première image. Utilisez const pour les widgets avec des paramètres fixes : icônes, titres, éléments décoratifs.

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

Questions fréquentes

En quoi le RenderObject Tree diffère-t-il du Widget Tree ?

Widget Tree est une configuration légère de l’interface qui est recréée à chaque reconstruction. RenderObject Tree est un arbre lourd d’objets de rendu qui persiste et se met à jour uniquement lorsque la géométrie ou l’apparence change.

Comment voir le RenderObject Tree dans le débogueur ?

Utilisez Flutter DevTools — l’onglet « Rendering ». Vous verrez les couches de rendu, les temps de layout et de paint, ainsi que des informations détaillées sur chaque RenderObject : tailles, contraintes et indicateurs de saleté.

Qu’est-ce qu’un RenderObject sale ?

Dirty est un RenderObject marqué comme nécessitant une mise à jour. L’indicateur _needsLayout ou _needsPaint est défini lorsque la configuration change, et Flutter effectue le layout ou le paint pour ce nœud à l’image suivante.

Puis-je créer mon propre RenderObject ?

Oui, créez une sous-classe de RenderBox et redéfinissez les méthodes performLayout et paint. Utilisez RenderObjectWidget pour intégrer un RenderObject personnalisé dans le Widget Tree. C’est une technique avancée pour un rendu non standard.

Comment RepaintBoundary affecte-t-il le RenderObject Tree ?

RepaintBoundary crée RenderRepaintBoundary, qui isole une partie du RenderObject Tree dans une couche séparée. Lorsque le contenu change, seule cette couche est repeinte, le reste de l’arbre restant inchangé.

Résumé

  • RenderObject Tree est le troisième niveau de l’architecture Flutter, responsable du layout et du paint de chaque élément de l’interface.
  • Chaque RenderObject effectue deux phases : layout (calcul des tailles et positions) et paint (dessin des pixels via Canvas).
  • RenderBox est le type de base pour les éléments standard, RenderSliver pour virtualiser les listes défilables.
  • RenderObject Tree est synchronisé avec l’Element Tree via RenderObjectElement, qui crée et met à jour les RenderObjects.
  • RepaintBoundary isole une partie de l’arbre dans une couche séparée, évitant un repeint complet de l’écran lors de modifications locales.
  • Les performances dépendent de la profondeur de l’arbre, du nombre de couches, du overdraw et de l’utilisation de constructeurs const.
  • Flutter DevTools fournit des outils pour analyser le RenderObject Tree : temps de layout, temps de paint, nombre de couches et de repeints.

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi