RenderObject Tree: چیست، اصل رندرینگ و نقش در Flutter

نویسنده: IT Sectr منتشر شده: 2026-07-01 زمان مطالعه: 9 دقیقه

RenderObject Tree — سومین سطح سلسله‌مراتب در Flutter است که مسئول رندرینگ واقعی رابط روی صفحه است. هر گره از این درخت محاسبه اندازه‌ها (layout) و رسم (painting) را انجام می‌دهد و پیکربندی ویجت‌ها را به پیکسل تبدیل می‌کند. برخلاف Widget Tree، RenderObject Tree یک بار ایجاد می‌شود و فقط با تغییر هندسه یا ظاهر به‌روزرسانی می‌شود. بر اساس Flutter API Reference, 2025, کارایی RenderObject Tree به طور مستقیم روانی انیمیشن‌ها و سرعت پاسخگویی برنامه را تعیین می‌کند.

نکات اصلی

  • RenderObject Tree — سلسله‌مراتب اشیاء رندرینگ که اندازه‌ها را محاسبه کرده و رابط را روی صفحه رسم می‌کنند.
  • هر RenderObject دو فاز انجام می‌دهد: layout (تعیین اندازه‌ها و موقعیت‌ها) و paint (رسم پیکسل‌ها).
  • RenderObject Tree از Element Tree ایجاد شده و از طریق عناصر با آن همگام‌سازی می‌شود.
  • RepaintBoundary بخشی از درخت را برای بازرسم محلی بدون تأثیر بر کل صفحه جدا می‌کند.
  • عملکرد RenderObject Tree به عمق، تعداد لایه‌ها و دفعات بازرسم بستگی دارد.

RenderObject Tree در Flutter چیست؟

RenderObject Tree — ساختار سلسله‌مراتبی از اشیاء رندرینگ است که نمایش واقعی رابط در حافظه محسوب می‌شود. هر RenderObject اندازه‌ها، موقعیت خود روی صفحه را می‌داند و قادر به رسم خود است. برخلاف ویجت‌ها که سبک‌وزن هستند و می‌توانند صدها بار در ثانیه بازسازی شوند، RenderObject — شیء سنگینی با دسترسی مستقیم به خط لوله گرافیکی است.

از پیکربندی تا رندرینگ

مسیر از ویجت به پیکسل سه مرحله را طی می‌کند: Widget Tree مشخص می‌کند چه چیزی روی صفحه باشد؛ Element Tree چرخه حیات را مدیریت می‌کند؛ RenderObject Tree کار واقعی را انجام می‌دهد. هر RenderObjectWidget (مانند Padding, Transform, CustomPaint) یک RenderObject ایجاد می‌کند که به درخت رندرینگ اضافه می‌شود. RenderBox — رایج‌ترین نوع RenderObject است که برای ۹۹٪ ویجت‌های استاندارد استفاده می‌شود.

معماری RenderObject

RenderObject — کلاس انتزاعی است که رابطی برای layout و paint تعریف می‌کند. این کلاس شامل ارجاع به RenderObject والد و اشیاء فرزند، و همچنین متدهای انتزاعی: performLayout, paint و hitTest است. هر RenderObject مشخص این متدها را مطابق با رفتار خود پیاده‌سازی می‌کند: RenderFlex فضا را بین عناصر فرزند توزیع می‌کند، RenderImage تصویر را نمایش می‌دهد، RenderParagraph متن را نمایش می‌دهد.

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

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

در این ساختار ساده‌شده، RenderObject شامل پرچم‌های _needsLayout و _needsPaint است که شیء را نیازمند به‌روزرسانی علامت‌گذاری می‌کنند. وقتی Widget Tree تغییر می‌کند، Element Tree RenderObjectهای مربوطه را به عنوان "کثیف" برای layout یا paint علامت‌گذاری می‌کند و در فریم بعدی Flutter فقط عملیات ضروری را انجام می‌دهد.

دو فاز RenderObject: layout و paint

هر RenderObject دو فاز کلیدی را انجام می‌دهد: layout (تعیین اندازه‌ها و موقعیت‌ها) و paint (رسم). این فازها به ترتیب دقیق اجرا می‌شوند: ابتدا layout برای کل درخت، سپس paint. اگر layout تغییر نکرده باشد، فاز paint می‌تواند حذف شود که باعث صرفه‌جویی در منابع GPU می‌شود.

فاز layout: محدودیت‌ها و اندازه‌ها

در طول layout، Flutter محدودیت‌ها (constraints) را از بالا به پایین در RenderObject Tree ارسال می‌کند. هر والد برای شیء فرزند حداقل و حداکثر عرض و ارتفاع را تعیین می‌کند. شیء فرزند اندازه خود را در چارچوب این محدودیت‌ها محاسبه کرده و به والد برمی‌گرداند. این فرآیند "downward pass" (انتقال محدودیت‌ها به پایین) و "upward pass" (انتقال اندازه‌ها به بالا) نامیده می‌شود.

  • BoxConstraints — رایج‌ترین نوع محدودیت: minWidth, maxWidth, minHeight, maxHeight.
  • SliverConstraints — در ScrollView برای مجازی‌سازی استفاده می‌شود: به محدودیت‌های استاندارد اطلاعاتی درباره اسکرول اضافه می‌شود.
  • RenderSliverMultiBoxAdaptor — layout لیست‌های مجازی‌شده را مدیریت کرده و فقط برای عناصر قابل مشاهده RenderObject ایجاد می‌کند.

فاز paint: نمایش روی صفحه

پس از اتمام layout، Flutter paint — رسم هر RenderObject را انجام می‌دهد. والد یک PaintingContext ایجاد کرده، آن را به اشیاء فرزند منتقل کرده و offset را مشخص می‌کند. هر RenderObject خود را روی Canvas با استفاده از ابتدایی‌های گرافیکی رسم می‌کند: مستطیل‌ها، دایره‌ها، متن، تصاویر و تبدیل‌ها. Canvas مستقیماً با Skia یا Impeller تعامل دارد.

علامت‌گذاری گره‌های کثیف

Flutter از مکانیزم گره‌های "کثیف" برای به حداقل رساندن کار استفاده می‌کند. وقتی فقط اندازه یک RenderObject تغییر می‌کند، Flutter layout کل درخت را دوباره محاسبه نمی‌کند — گره تغییرکرده و اجداد احتمالی آن را تا نزدیک‌ترین RenderBox با اندازه ثابت علامت‌گذاری می‌کند. به طور مشابه، با تغییر ظاهر، فقط paint بدون تکرار layout علامت‌گذاری می‌شود.

انواع RenderObject در Flutter

Flutter ارائه می‌دهد چندین دسته RenderObject برای وظایف مختلف: RenderBox برای عناصر مستطیلی استاندارد، RenderSliver برای نواحی اسکرول‌شدنی و RenderObject سفارشی برای رندرینگ غیراستاندارد از طریق CustomPainter. هر نوع برای نقش خود در درخت رندرینگ بهینه‌سازی شده است.

RenderBox و زیرنوع‌های آن

RenderBox — کلاس پایه برای عناصر مستطیلی رابط. زیرنوع‌های آن: RenderPadding (افزودن فاصله), RenderTransform (اعمال تبدیل‌ها), RenderFlex (پیاده‌سازی Row و Column), RenderStack (قرارگیری عناصر روی هم), RenderImage (نمایش تصاویر), RenderParagraph (نمایش متن). هر زیرنوع performLayout و paint را برای منطق خود بازنویسی می‌کند.

RenderSliver و مجازی‌سازی

RenderSliver — نوعی RenderObject برای کار با نواحی اسکرول‌شدنی است. برخلاف RenderBox، Sliver از SliverConstraints استفاده می‌کند که شامل اطلاعاتی درباره ناحیه قابل مشاهده (viewport) است. RenderSliverList و RenderSliverGrid فقط برای عناصری که در ناحیه قابل مشاهده قرار می‌گیرند RenderObject ایجاد می‌کنند که امکان پردازش لیست‌هایی با میلیون‌ها رکورد را فراهم می‌کند.

RenderObject سفارشی از طریق CustomPainter

برای گرافیک غیراستاندارد از CustomPaint و CustomPainter استفاده کنید. CustomPaint یک RenderCustomPaint ایجاد می‌کند که متدهای paint را در CustomPainter فراخوانی می‌کند. این امکان رسم اشکال دلخواه، نمودارها و انیمیشن‌ها با کنترل کامل روی Canvas را فراهم می‌کند. به گفته Flutter Team، CustomPainter برای گرافیک برداری پیچیده از ویجت‌های استاندارد تو در تو کارآمدتر است.

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

در این مثال، CirclePainter یک دایره روی Canvas رسم می‌کند. متد shouldRepaint فقط با تغییر رنگ true برمی‌گرداند که از بازرسم غیرضروری جلوگیری می‌کند. CustomPainter باید تا حد امکان سبک باشد — تمام محاسبات سنگین را خارج از متدهای paint انجام دهید.

RenderObject Tree از Element Tree از طریق مکانیزم RenderObjectWidget ایجاد می‌شود. هر RenderObjectWidget (Padding, Transform, CustomPaint) یک RenderObjectElement ایجاد می‌کند که RenderObject مربوطه را ایجاد و مدیریت می‌کند. عنصر نقش واسطه را ایفا می‌کند: پیکربندی را از ویجت به RenderObject منتقل کرده و RenderObject را از تغییرات مطلع می‌کند.

ایجاد RenderObject از عنصر

وقتی RenderObjectElement نصب می‌شود، متد createRenderObject ویجت خود را فراخوانی می‌کند. ویجت یک نمونه RenderObject ایجاد کرده و به عنصر برمی‌گرداند. عنصر با فراخوانی متد insertChildLayout در RenderObject والد، RenderObject را در RenderObject Tree جاسازی می‌کند. این فرآیند فقط در اولین نصب رخ می‌دهد — در به‌روزرسانی‌های بعدی، عنصر فقط پارامترهای RenderObject موجود را به‌روزرسانی می‌کند.

همگام‌سازی از طریق updateRenderObject

وقتی پیکربندی ویجت تغییر می‌کند (مثلاً مقدار padding تغییر می‌کند)، عنصر متد updateRenderObject را فراخوانی می‌کند که پیکربندی جدید را به RenderObject موجود منتقل می‌کند. RenderObject خود را برای layout یا paint به عنوان "کثیف" علامت‌گذاری می‌کند و در فریم بعدی فریم‌ورک به‌روزرسانی‌های لازم را انجام می‌دهد.

حذف RenderObject

هنگام جدا کردن عنصر، متد unmount فراخوانی می‌شود که RenderObject را از RenderObject Tree حذف کرده و منابع را آزاد می‌کند. RenderObject.remove برای جدا کردن از والد فراخوانی می‌شود، پس از آن شیء می‌تواند توسط جمع‌آوری زباله جمع‌آوری شود. Flutter تضمین می‌کند که RenderObject بدون عنصر مربوطه در درخت باقی نمی‌ماند.

RepaintBoundary و جداسازی رندرینگ

RepaintBoundary — ویجتی است که یک لایه جداگانه برای رندرینگ محتوای خود ایجاد می‌کند. وقتی محتوای RepaintBoundary تغییر می‌کند، فقط این لایه بازرسم می‌شود و بقیه قسمت‌های صفحه بدون تغییر می‌مانند. RepaintBoundary به ویژه برای انیمیشن‌ها، پخش‌کننده‌های ویدئو، نمودارهای تعاملی و سایر عناصر مکرراً به‌روزرسانی‌شونده مفید است.

چگونه RepaintBoundary کار می‌کند

در هسته RepaintBoundary، RenderRepaintBoundary — یک RenderObject ویژه قرار دارد که یک PictureLayer جداگانه ایجاد می‌کند. در اولین رندرینگ، RenderRepaintBoundary دستورات گرافیکی را در این لایه ضبط می‌کند. در به‌روزرسانی‌های بعدی، اگر فقط محتوای داخل RepaintBoundary تغییر کرده باشد، Flutter فقط این لایه را بازرسم می‌کند، نه کل صفحه را. بقیه لایه‌ها بدون تغییر باقی مانده و دوباره استفاده می‌شوند.

چه زمانی از RepaintBoundary استفاده کنیم

هر ویجتی به RepaintBoundary نیاز ندارد. وقتی بخشی از رابط با فرکانس بالا (۶۰ FPS و بالاتر) به‌روزرسانی می‌شود و بقیه صفحه ثابت است، از آن استفاده کنید. مثال‌های معمول: نشانگر بارگذاری متحرک، پخش‌کننده ویدئو، Canvas بازی، CustomPainter با بازرسم مکرر. برای متن ثابت یا دکمه‌ها، RepaintBoundary اضافی است و فقط مصرف حافظه را افزایش می‌دهد.

سناریوتوصیهدلیل
انیمیشندر RepaintBoundary بپیچیدناحیه مکرراً به‌روزرسانی‌شونده را جدا می‌کند
لیست اسکرول‌شدنینیاز نیستListView به طور خودکار از لایه‌ها استفاده می‌کند
متن ثابتنیاز نیستبازرسم مکرر وجود ندارد
CustomPainterتوصیه می‌شودبازرسم مکرر گرافیک

بهینه‌سازی RenderObject Tree برای عملکرد

عملکرد RenderObject Tree به تعداد گره‌ها، عمق درخت و دفعات بازرسم بستگی دارد. ابزارهای Flutter DevTools (برگه "Rendering") امکان تحلیل RenderObject Tree را در زمان واقعی فراهم می‌کنند: تعداد repaint، زمان layout و paint، تعداد لایه‌ها و اندازه‌های آنها. تحلیل منظم به شناسایی تنگناها کمک می‌کند.

از overdraw بیش از حد خودداری کنید

Overdraw — وضعیتی است که یک پیکسل چندین بار در هر فریم رسم می‌شود. مثلاً وقتی یک ویجت نیمه‌شفاف روی ویجت دیگر قرار می‌گیرد، GPU هر دو لایه را رسم می‌کند. از پرچم‌های opaque (Container با color به جای decoration) برای عناصر غیرشفاف استفاده کنید تا Flutter لایه‌های نامرئی را نادیده بگیرد. به گفته Flutter Team، کاهش overdraw می‌تواند زمان paint را تا ۳۰٪ کاهش دهد.

تعداد لایه‌ها را به حداقل برسانید

هر RepaintBoundary و برخی ویجت‌ها (Opacity, ClipRRect, Transform) یک لایه جداگانه (PictureLayer) ایجاد می‌کنند. لایه‌های زیاد زمان ترکیب را افزایش می‌دهند. از گروه‌بندی استفاده کنید: به جای چند Opacity روی ویجت‌های جداگانه، یک Opacity روی کانتینر اعمال کنید. به جای ClipRRect روی هر عنصر، از ClipRRect روی کانتینر مشترک استفاده کنید.

از const-سازنده‌ها استفاده کنید

وقتی ویجت به عنوان const اعلام می‌شود، Flutter می‌داند که پیکربندی آن تغییر نخواهد کرد و می‌تواند RenderObject مربوطه را بدون بازسازی دوباره استفاده کند. سازنده‌های const بار جمع‌آوری زباله را کاهش داده و اولین فریم را سرعت می‌بخشند. برای ویجت‌هایی با پارامترهای ثابت از const استفاده کنید: آیکون‌ها، عنوان‌ها، عناصر تزئینی.

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

سوالات متداول

RenderObject Tree چه تفاوتی با Widget Tree دارد؟

Widget Tree — پیکربندی سبک رابط است که در هر rebuild بازسازی می‌شود. RenderObject Tree — درخت سنگینی از اشیاء رندرینگ است که حفظ شده و فقط با تغییر هندسه یا ظاهر به‌روزرسانی می‌شود.

چگونه RenderObject Tree را در دیباگر ببینیم؟

از Flutter DevTools — برگه "Rendering" استفاده کنید. لایه‌های رندرینگ، زمان layout و paint و همچنین اطلاعات دقیق درباره هر RenderObject را مشاهده خواهید کرد: اندازه‌ها، constraints، پرچم‌های نیاز به به‌روزرسانی.

dirty RenderObject چیست؟

Dirty — RenderObjectی است که به عنوان نیازمند به‌روزرسانی علامت‌گذاری شده است. پرچم _needsLayout یا _needsPaint با تغییر پیکربندی تنظیم می‌شود و Flutter در فریم بعدی layout یا paint را برای این گره انجام می‌دهد.

آیا می‌توان RenderObject خود را ایجاد کرد؟

بله، یک زیرکلاس از RenderBox ایجاد کرده و متدهای performLayout و paint را بازنویسی کنید. از RenderObjectWidget برای جاسازی RenderObject سفارشی در Widget Tree استفاده کنید. این یک تکنیک پیشرفته برای رندرینگ غیراستاندارد است.

RepaintBoundary چگونه بر RenderObject Tree تأثیر می‌گذارد؟

RepaintBoundary یک RenderRepaintBoundary ایجاد می‌کند که بخشی از RenderObject Tree را در یک لایه جداگانه ایزوله می‌کند. با تغییر محتوا، فقط این لایه بازرسم می‌شود و بقیه درخت بدون تغییر می‌ماند.

خلاصه

  • RenderObject Tree — سومین سطح معماری Flutter، مسئول layout و paint هر عنصر رابط.
  • هر RenderObject دو فاز انجام می‌دهد: layout (محاسبه اندازه‌ها و موقعیت‌ها) و paint (رسم پیکسل‌ها از طریق Canvas).
  • RenderBox — نوع پایه برای عناصر استاندارد، RenderSliver — برای مجازی‌سازی لیست‌های اسکرول‌شدنی.
  • RenderObject Tree از طریق RenderObjectElement با Element Tree همگام‌سازی می‌شود که RenderObject را ایجاد و به‌روزرسانی می‌کند.
  • RepaintBoundary بخشی از درخت را در یک لایه جداگانه ایزوله می‌کند و از بازرسم کامل صفحه در تغییرات محلی جلوگیری می‌کند.
  • عملکرد به عمق درخت، تعداد لایه‌ها، overdraw و استفاده از const-سازنده‌ها بستگی دارد.
  • Flutter DevTools ابزارهایی برای تحلیل RenderObject Tree ارائه می‌دهد: زمان layout، paint، تعداد لایه‌ها و repaint.

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید