RenderObject Tree — adalah tingkat ketiga hierarki di Flutter, yang bertanggung jawab atas rendering aktual antarmuka di layar. Setiap simpul pohon ini melakukan perhitungan ukuran (layout) dan menggambar (painting), mengubah konfigurasi widget menjadi piksel. Berbeda dengan Widget Tree, RenderObject Tree dibuat sekali dan diperbarui hanya saat geometri atau tampilan berubah. Menurut Flutter API Reference, 2025, efisiensi RenderObject Tree secara langsung menentukan kehalusan animasi dan kecepatan respons aplikasi.
Poin utama
RenderObject Tree — adalah struktur hierarkis objek rendering yang merupakan representasi aktual antarmuka di memori. Setiap RenderObject mengetahui ukuran, posisi di layar, dan dapat menggambar dirinya sendiri. Berbeda dengan widget yang ringan dan dapat dibuat ulang ratusan kali per detik, RenderObject — adalah objek berat dengan akses langsung ke pipa grafis.
Jalur dari widget ke piksel melalui tiga tahap: Widget Tree menggambarkan apa yang seharusnya ada di layar; Element Tree mengelola siklus hidup; RenderObject Tree melakukan pekerjaan aktual. Setiap RenderObjectWidget (misalnya, Padding, Transform, CustomPaint) membuat RenderObject yang ditambahkan ke pohon rendering. RenderBox — jenis RenderObject yang paling umum, digunakan untuk 99% widget standar.
RenderObject — adalah kelas abstrak yang mendefinisikan antarmuka untuk layout dan paint. Ini berisi referensi ke RenderObject induk dan objek anak, serta metode abstrak: performLayout, paint dan hitTest. Setiap RenderObject konkret mengimplementasikan metode ini sesuai dengan perilakunya: RenderFlex mendistribusikan ruang di antara elemen anak, RenderImage menampilkan gambar, RenderParagraph menampilkan teks.
abstract class RenderObject {
RenderObject? parent;
Constraints constraints;
ParentData? parentData;
bool _needsLayout = true;
bool _needsPaint = true;
void performLayout();
void paint(PaintingContext context, Offset offset);
}
Dalam struktur yang disederhanakan ini, RenderObject berisi bendera _needsLayout dan _needsPaint yang menandai objek sebagai memerlukan pembaruan. Saat Widget Tree berubah, Element Tree menandai RenderObject yang sesuai sebagai "kotor" untuk layout atau paint, dan pada frame berikutnya Flutter hanya menjalankan operasi yang diperlukan.
Setiap RenderObject menjalankan dua fase utama: layout (menentukan ukuran dan posisi) dan paint (menggambar). Fase-fase ini dijalankan dalam urutan ketat: pertama layout untuk seluruh pohon, kemudian paint. Fase paint dapat dilewati jika layout tidak berubah, yang menghemat sumber daya GPU.
Selama layout, Flutter mengirimkan batasan (constraints) dari atas ke bawah melalui RenderObject Tree. Setiap induk menetapkan untuk objek anak lebar dan tinggi minimum dan maksimum. Objek anak menghitung ukurannya dalam batasan ini dan mengembalikannya ke induk. Proses ini disebut "downward pass" (pengiriman batasan ke bawah) dan "upward pass" (pengiriman ukuran ke atas).
Setelah layout selesai, Flutter menjalankan paint — menggambar setiap RenderObject. Induk membuat PaintingContext, mengirimkannya ke objek anak dan menentukan offset. Setiap RenderObject menggambar dirinya sendiri di Canvas menggunakan primitif grafis: persegi panjang, lingkaran, teks, gambar, dan transformasi. Canvas berinteraksi langsung dengan Skia atau Impeller.
Flutter menggunakan mekanisme simpul "kotor" untuk meminimalkan pekerjaan. Ketika hanya ukuran satu RenderObject berubah, Flutter tidak menghitung ulang layout seluruh pohon — ia menandai simpul yang berubah dan kemungkinan leluhurnya hingga RenderBox terdekat dengan ukuran tetap. Demikian pula, saat tampilan berubah, hanya paint yang ditandai tanpa mengulangi layout.
Flutter menyediakan beberapa kategori RenderObject untuk tugas yang berbeda: RenderBox untuk elemen persegi panjang standar, RenderSliver untuk area yang dapat digulir, dan RenderObject kustom untuk rendering tidak standar melalui CustomPainter. Setiap jenis dioptimalkan untuk perannya di pohon rendering.
RenderBox — kelas dasar untuk elemen antarmuka persegi panjang. Subtipe-subtipenya: RenderPadding (menambahkan spasi), RenderTransform (menerapkan transformasi), RenderFlex (mengimplementasikan Row dan Column), RenderStack (menumpuk elemen), RenderImage (menampilkan gambar), RenderParagraph (menampilkan teks). Setiap subtipe menimpa performLayout dan paint untuk logikanya sendiri.
RenderSliver — adalah jenis RenderObject untuk bekerja dengan area yang dapat digulir. Berbeda dengan RenderBox, Sliver menggunakan SliverConstraints yang mencakup informasi tentang area yang terlihat (viewport). RenderSliverList dan RenderSliverGrid membuat RenderObject hanya untuk elemen yang berada di area yang terlihat, memungkinkan pemrosesan daftar dengan jutaan catatan.
Untuk grafis tidak standar, gunakan CustomPaint dan CustomPainter. CustomPaint membuat RenderCustomPaint yang memanggil metode paint di CustomPainter. Ini memungkinkan menggambar bentuk arbitrer, grafik, dan animasi dengan kontrol penuh atas Canvas. Menurut Flutter Team, CustomPainter lebih efisien daripada widget standar bersarang untuk grafis vektor kompleks.
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;
}
Dalam contoh ini, CirclePainter menggambar lingkaran di Canvas. Metode shouldRepaint mengembalikan true hanya saat warna berubah, mencegah penggambaran ulang yang tidak perlu. CustomPainter harus seringan mungkin — semua perhitungan berat dilakukan di luar metode paint.
RenderObject Tree dibuat dari Element Tree melalui mekanisme RenderObjectWidget. Setiap RenderObjectWidget (Padding, Transform, CustomPaint) membuat RenderObjectElement yang membuat dan mengelola RenderObject yang sesuai. Elemen bertindak sebagai perantara: ia meneruskan konfigurasi dari widget ke RenderObject dan memberi tahu RenderObject tentang perubahan.
Saat RenderObjectElement dipasang, ia memanggil metode createRenderObject dari widgetnya. Widget membuat instance RenderObject dan mengembalikannya ke elemen. Elemen menyematkan RenderObject ke RenderObject Tree dengan memanggil metode insertChildLayout pada RenderObject induk. Proses ini hanya terjadi pada pemasangan pertama — pada pembaruan berikutnya, elemen hanya memperbarui parameter RenderObject yang ada.
Saat konfigurasi widget berubah (misalnya, nilai padding berubah), elemen memanggil metode updateRenderObject, yang meneruskan konfigurasi baru ke RenderObject yang ada. RenderObject menandai dirinya sebagai "kotor" untuk layout atau paint, dan pada frame berikutnya framework melakukan pembaruan yang diperlukan.
Saat elemen dibongkar, metode unmount dipanggil, yang menghapus RenderObject dari RenderObject Tree dan membebaskan sumber daya. RenderObject.remove dipanggil untuk memutuskan dari induk, setelah itu objek dapat dikumpulkan oleh pengumpul sampah. Flutter menjamin bahwa RenderObject tidak menggantung di pohon tanpa elemen yang sesuai.
RepaintBoundary — adalah widget yang membuat lapisan terpisah untuk rendering kontennya. Saat konten RepaintBoundary berubah, hanya lapisan ini yang digambar ulang, dan bagian lain layar tetap tidak berubah. RepaintBoundary sangat berguna untuk animasi, pemutar video, grafik interaktif, dan elemen lain yang sering diperbarui.
Di dasar RepaintBoundary terdapat RenderRepaintBoundary — RenderObject khusus yang membuat PictureLayer terpisah. Pada rendering pertama, RenderRepaintBoundary mencatat perintah grafis ke lapisan ini. Pada pembaruan berikutnya, jika hanya konten di dalam RepaintBoundary yang berubah, Flutter hanya menggambar ulang lapisan ini, bukan seluruh layar. Lapisan lainnya tetap tidak berubah dan digunakan kembali.
Tidak setiap widget membutuhkan RepaintBoundary. Gunakan ketika bagian antarmuka diperbarui dengan frekuensi tinggi (60 FPS dan lebih), sementara sisa layar statis. Contoh tipikal: indikator pemuatan animasi, pemutar video, Canvas game, CustomPainter dengan penggambaran ulang sering. Untuk teks statis atau tombol, RepaintBoundary berlebihan dan hanya meningkatkan konsumsi memori.
| Skenario | Rekomendasi | Alasan |
|---|---|---|
| Animasi | Bungkus dalam RepaintBoundary | Mengisolasi area yang sering diperbarui |
| Daftar gulir | Tidak diperlukan | ListView menggunakan lapisan secara otomatis |
| Teks statis | Tidak diperlukan | Tidak ada penggambaran ulang sering |
| CustomPainter | Disarankan | Penggambaran ulang grafis sering |
Kinerja RenderObject Tree tergantung pada jumlah simpul, kedalaman pohon, dan frekuensi penggambaran ulang. Alat Flutter DevTools (tab "Rendering") memungkinkan analisis RenderObject Tree secara real-time: jumlah repaint, waktu layout dan paint, jumlah lapisan dan ukurannya. Analisis rutin membantu mengidentifikasi hambatan.
Overdraw — adalah situasi di mana satu piksel digambar beberapa kali per frame. Misalnya, ketika widget semi-transparan ditempatkan di atas widget lain, GPU menggambar kedua lapisan. Gunakan bendera opaque (Container dengan color bukan decoration) untuk elemen buram agar Flutter melewati lapisan yang tidak terlihat. Menurut Flutter Team, mengurangi overdraw dapat mempersingkat waktu paint hingga 30%.
Setiap RepaintBoundary dan beberapa widget (Opacity, ClipRRect, Transform) membuat lapisan terpisah (PictureLayer). Terlalu banyak lapisan meningkatkan waktu komposisi. Gunakan pengelompokan: daripada beberapa Opacity pada widget terpisah, terapkan satu Opacity pada wadah. Daripada ClipRRect pada setiap elemen, gunakan ClipRRect pada wadah bersama.
Saat widget dideklarasikan sebagai const, Flutter tahu bahwa konfigurasinya tidak akan berubah dan dapat menggunakan kembali RenderObject yang sesuai tanpa membuat ulang. Konstruktor const mengurangi beban pada pengumpul sampah dan mempercepat frame pertama. Gunakan const untuk widget dengan parameter tetap: ikon, judul, elemen dekoratif.
const Text("Judul", style: TextStyle(fontSize: 24));
const Icon(Icons.home, color: Colors.blue);
const SizedBox.shrink();
Pertanyaan yang sering diajukan
Widget Tree — adalah konfigurasi antarmuka ringan yang dibuat ulang setiap rebuild. RenderObject Tree — adalah pohon berat objek rendering yang disimpan dan diperbarui hanya saat geometri atau tampilan berubah.
Gunakan Flutter DevTools — tab "Rendering". Anda akan melihat lapisan rendering, waktu layout dan paint, serta informasi detail tentang setiap RenderObject: ukuran, constraints, bendera kebutuhan pembaruan.
Dirty — adalah RenderObject yang ditandai sebagai memerlukan pembaruan. Bendera _needsLayout atau _needsPaint diatur saat konfigurasi berubah, dan Flutter menjalankan layout atau paint untuk simpul ini di frame berikutnya.
Ya, buat subkelas dari RenderBox dan timpa metode performLayout dan paint. Gunakan RenderObjectWidget untuk menyematkan RenderObject kustom ke Widget Tree. Ini adalah teknik lanjutan untuk rendering tidak standar.
RepaintBoundary membuat RenderRepaintBoundary yang mengisolasi bagian RenderObject Tree ke dalam lapisan terpisah. Saat konten berubah, hanya lapisan ini yang digambar ulang dan sisa pohon tetap tidak berubah.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga