RenderObject Tree é o terceiro nível da hierarquia do Flutter, responsável pela renderização real da interface na tela. Cada nó desta árvore realiza o cálculo de tamanhos (layout) e a pintura (painting), convertendo a configuração dos widgets em pixels. Ao contrário da Widget Tree, a RenderObject Tree é criada uma vez e atualizada apenas quando a geometria ou a aparência mudam. De acordo com a Referência da API Flutter, 2025, a eficiência da RenderObject Tree determina diretamente a suavidade das animações e a capacidade de resposta da aplicação.
Pontos principais
RenderObject Tree é uma estrutura hierárquica de objetos de renderização que serve como a representação real da interface na memória. Cada RenderObject conhece seu próprio tamanho, posição na tela e como se desenhar. Ao contrário dos widgets, que são leves e podem ser recriados centenas de vezes por segundo, um RenderObject é um objeto pesado com acesso direto ao pipeline gráfico.
O caminho do widget aos pixels passa por três etapas: a Widget Tree descreve o que deve estar na tela; a Element Tree gerencia o ciclo de vida; a RenderObject Tree realiza o trabalho real. Cada RenderObjectWidget (como Padding, Transform, CustomPaint) cria um RenderObject que é adicionado à árvore de renderização. RenderBox é o tipo mais comum de RenderObject, usado por 99% dos widgets padrão.
RenderObject é uma classe abstrata que define a interface para layout e paint. Ela contém referências ao RenderObject pai e aos objetos filhos, bem como métodos abstratos: performLayout, paint e hitTest. Cada RenderObject concreto implementa esses métodos de acordo com seu comportamento: RenderFlex distribui espaço entre os filhos, RenderImage exibe uma imagem, RenderParagraph renderiza texto.
abstract class RenderObject {
RenderObject? parent;
Constraints constraints;
ParentData? parentData;
bool _needsLayout = true;
bool _needsPaint = true;
void performLayout();
void paint(PaintingContext context, Offset offset);
}
Nesta estrutura simplificada, RenderObject contém os flags _needsLayout e _needsPaint, que marcam o objeto como necessitando de atualização. Quando a Widget Tree muda, a Element Tree marca os RenderObjects correspondentes como “ sujos” para layout ou paint, e no próximo frame o Flutter realiza apenas as operações necessárias.
Cada RenderObject realiza duas fases principais: layout (determinação de tamanhos e posições) e paint (desenho). Essas fases são executadas em ordem estrita: primeiro layout para toda a árvore, depois paint. A fase de paint pode ser pulada se o layout não mudou, economizando recursos da GPU.
Durante o layout, o Flutter passa restrições (constraints) de cima para baixo através da RenderObject Tree. Cada pai define largura e altura mínima e máxima para seu filho. O filho calcula seu tamanho dentro dessas restrições e o retorna ao pai. Este processo é chamado de “passagem descendente” (passar restrições para baixo) e “passagem ascendente” (passar tamanhos para cima).
Após completar o layout, o Flutter realiza o paint — desenho de cada RenderObject. O pai cria um PaintingContext, passa para os objetos filhos e especifica o deslocamento (offset). Cada RenderObject se desenha no Canvas usando primitivas gráficas: retângulos, círculos, texto, imagens e transformações. O Canvas interage diretamente com Skia ou Impeller.
O Flutter usa um mecanismo de nós “sujos” para minimizar o trabalho. Quando apenas o tamanho de um RenderObject muda, o Flutter não recalcula o layout de toda a árvore — ele marca o nó alterado e seus possíveis ancestrais até o RenderBox mais próximo com tamanho fixo. Da mesma forma, quando a aparência muda, apenas o paint é marcado sem refazer o layout.
O Flutter fornece várias categorias de RenderObject para diferentes tarefas: RenderBox para elementos retangulares padrão, RenderSliver para áreas roláveis e RenderObjects personalizados para renderização não padrão via CustomPainter. Cada tipo é otimizado para seu papel na árvore de renderização.
RenderBox é a classe base para elementos de interface retangulares. Seus subtipos incluem: RenderPadding (adiciona preenchimento), RenderTransform (aplica transformações), RenderFlex (implementa Row e Column), RenderStack (sobrepõe elementos), RenderImage (exibe imagens), RenderParagraph (renderiza texto). Cada subtipo substitui performLayout e paint para sua própria lógica.
RenderSliver é um tipo de RenderObject para trabalhar com áreas roláveis. Ao contrário do RenderBox, o Sliver usa SliverConstraints, que incluem informações do viewport. RenderSliverList e RenderSliverGrid criam RenderObjects apenas para os itens na área visível, permitindo lidar com listas com milhões de entradas.
Para gráficos não padrão, use CustomPaint e CustomPainter. CustomPaint cria RenderCustomPaint, que chama os métodos paint do CustomPainter. Isso permite desenhar formas arbitárias, gráficos e animações com controle total sobre o Canvas. De acordo com a equipe do Flutter, o CustomPainter é mais eficiente que widgets padrão aninhados para gráficos vetoriais complexos.
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;
}
Neste exemplo, CirclePainter desenha um círculo no Canvas. O método shouldRepaint retorna true apenas quando a cor muda, evitando repinturas desnecessárias. O CustomPainter deve ser o mais leve possível — realize todos os cálculos pesados fora dos métodos paint.
RenderObject Tree é criada a partir da Element Tree através do mecanismo RenderObjectWidget. Cada RenderObjectWidget (Padding, Transform, CustomPaint) cria um RenderObjectElement, que por sua vez cria e gerencia o RenderObject correspondente. O elemento atua como intermediário: passa a configuração do widget para o RenderObject e notifica o RenderObject sobre as mudanças.
Quando um RenderObjectElement é montado, ele chama o método createRenderObject em seu widget. O widget cria uma instância de RenderObject e a retorna ao elemento. O elemento insere o RenderObject na RenderObject Tree chamando o método insertChildLayout no RenderObject pai. Este processo ocorre apenas na primeira montagem — em atualizações subsequentes, o elemento simplesmente atualiza os parâmetros do RenderObject existente.
Quando a configuração do widget muda (por exemplo, o valor de padding muda), o elemento chama o método updateRenderObject, que passa a nova configuração ao RenderObject existente. O RenderObject se marca como “ sujo” para layout ou paint, e no próximo frame o framework realiza as atualizações necessárias.
Quando um elemento é desmontado, o método unmount é chamado, que remove o RenderObject da RenderObject Tree e libera recursos. RenderObject.remove é chamado para se desconectar do pai, após o qual o objeto pode ser coletado pelo coletor de lixo. O Flutter garante que nenhum RenderObject fique pendurado na árvore sem um elemento correspondente.
RepaintBoundary é um widget que cria uma camada separada para renderizar seu conteúdo. Quando o conteúdo dentro de um RepaintBoundary muda, apenas essa camada é repintada, enquanto o resto da tela permanece inalterado. RepaintBoundary é especialmente útil para animações, players de vídeo, gráficos interativos e outros elementos atualizados com frequência.
No núcleo do RepaintBoundary está RenderRepaintBoundary — um RenderObject especial que cria um PictureLayer separado. Na primeira renderização, o RenderRepaintBoundary grava comandos gráficos nesta camada. Em atualizações subsequentes, se apenas o conteúdo dentro do RepaintBoundary mudar, o Flutter repinta apenas esta camada em vez de toda a tela. As outras camadas permanecem inalteradas e são reutilizadas.
Nem todo widget precisa de RepaintBoundary. Use-o quando uma parte da interface atualiza com alta frequência (60 FPS ou mais) enquanto o resto da tela é estático. Exemplos típicos: um indicador de carregamento animado, player de vídeo, Canvas de jogo, CustomPainter com repinturas frequentes. Para texto estático ou botões, RepaintBoundary é excessivo e só aumenta o consumo de memória.
| Cenário | Recomendação | Motivo |
|---|---|---|
| Animação | Envolver em RepaintBoundary | Isola a área frequentemente atualizada |
| Lista rolável | Não necessário | ListView usa camadas automaticamente |
| Texto estático | Não necessário | Sem repinturas frequentes |
| CustomPainter | Recomendado | Repinturas gráficas frequentes |
O desempenho da RenderObject Tree depende do número de nós, profundidade da árvore e frequência de repintura. O Flutter DevTools (a aba “Rendering”) permite analisar a RenderObject Tree em tempo real: contagem de repinturas, tempo de layout e paint, número de camadas e seus tamanhos. A análise regular ajuda a identificar gargalos.
Overdraw é uma situação em que um único pixel é desenhado várias vezes por frame. Por exemplo, quando um widget semitransparente se sobrepõe a outro, a GPU desenha ambas as camadas. Use flags opacos (Container com color em vez de decoration) para elementos não transparentes, para que o Flutter pule camadas invisíveis. De acordo com a equipe do Flutter, reduzir o overdraw pode diminuir o tempo de paint em até 30%.
Cada RepaintBoundary e alguns widgets (Opacity, ClipRRect, Transform) criam uma camada separada (PictureLayer). Muitas camadas aumentam o tempo de composição. Use agrupamento: em vez de vários widgets Opacity em elementos individuais, aplique um único Opacity ao contêiner. Em vez de ClipRRect em cada elemento, use ClipRRect no contêiner comum.
Quando um widget é declarado como const, o Flutter sabe que sua configuração não mudará e pode reutilizar o RenderObject correspondente sem recriá-lo. Construtores const reduzem a carga do coletor de lixo e aceleram o primeiro frame. Use const para widgets com parâmetros fixos: ícones, títulos, elementos decorativos.
const Text("Title", style: TextStyle(fontSize: 24));
const Icon(Icons.home, color: Colors.blue);
const SizedBox.shrink();
Perguntas frequentes
Widget Tree é uma configuração leve de interface que é recriada a cada reconstrução. RenderObject Tree é uma árvore pesada de objetos de renderização que persiste e atualiza apenas quando a geometria ou aparência muda.
Use Flutter DevTools — a aba “Rendering”. Você verá as camadas de renderização, tempo de layout e paint, e informações detalhadas de cada RenderObject: tamanhos, restrições e flags sujos.
Dirty é um RenderObject marcado como necessitando de atualização. O flag _needsLayout ou _needsPaint é definido quando a configuração muda, e o Flutter realiza layout ou paint para aquele nó no próximo frame.
Sim, crie uma subclasse de RenderBox e substitua os métodos performLayout e paint. Use RenderObjectWidget para incorporar um RenderObject personalizado na Widget Tree. Esta é uma técnica avançada para renderização não padrão.
RepaintBoundary cria RenderRepaintBoundary, que isola parte da RenderObject Tree em uma camada separada. Quando o conteúdo muda, apenas essa camada é repintada, deixando o resto da árvore inalterado.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também