Widget Tree: چیست، ساختار و نقش در درخت ویجت‌ها

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

Widget Tree «ساختار سلسله‌مراتبی ویجت‌ها در Flutter است که ترکیب رابط کاربری را تعیین می‌کند. هر عنصر رابط، از دکمه گرفته تا کل صفحه، توسط یک ویجت جداگانه که در کانتینر والد قرار گرفته است، نمایش داده می‌شود. Flutter در هر تغییر وضعیت، Widget Tree را به‌روزرسانی می‌کند » فریمورک درخت جدید و قدیم را مقایسه کرده و حداقل تغییرات را اعمال می‌کند. بر اساس داده‌های Flutter Team, 2025، ساختار مؤثر درخت به‌طور مستقیم بر روانی انیمیشن‌ها و سرعت پاسخگویی رابط تأثیر می‌گذارد.

نکات اصلی

  • Widget Tree «سلسله‌مراتبی است که در آن هر ویجت Flutter یک گره است و تودرتو بودن ترکیب UI را منعکس می‌کند.
  • هر rebuild پیکربندی ویجت‌ها را بازآفرینی می‌کند، اما لزوماً صفحه را دوباره ترسیم نمی‌کند » Element و RenderObject مسئول این کار هستند.
  • StatelessWidget وضعیت داخلی ندارد، در حالی که StatefulWidget داده‌هایی را ذخیره می‌کند که بر rebuild درخت تأثیر می‌گذارند.
  • کلیدها (Key) به Flutter کمک می‌کنند ویجت‌ها را هنگام بازسازی شناسایی کند و از از دست رفتن وضعیت جلوگیری می‌کنند.
  • عمق درخت بر عملکرد تأثیر می‌گذارد » تودرتو بودن بیش ازحد می‌تواند فاز layout رندرینگ را کند کند.

Widget Tree در Flutter چیست؟

Widget Tree «توصیف اعلانی رابط کاربری در Flutter است که به صورت درختی از ویجت‌های تودرتو ساخته شده است. هر ویجت بخشی از UI را تعیین می‌کند: پیکربندی، پارامترهای نمایش و رفتار آن در هنگام تعامل. توسعه‌دهنده توصیف می‌کند که رابط باید در وضعیت فعلی برنامه چگونه به نظر برسد و Flutter مسئول تبدیل این توصیف به پیکسل‌ها روی صفحه است.

رویکرد اعلانی Flutter

برخلاف فریمورک‌های امری که توسعه‌دهنده مستقیماً عناصر رابط را دستکاری می‌کند، Flutter از رویکرد اعلانی استفاده می‌کند. با تغییر وضعیت برنامه، یک Widget Tree جدید ایجاد می‌شود و فریمورک تفاوت بین درخت قدیم و جدید را محاسبه می‌کند. این کار تعداد عملیات ترسیم را به حداقل می‌رساند و کد را قابل‌پیش‌بینی‌تر می‌کند.

dart
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Widget Tree")),
        body: Center(
          child: Column(
            children: [
              Text("سلام، Flutter"),
              ElevatedButton(
                onPressed: () {},
                child: Text("مرا فشار بده"),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

در این مثال، Widget Tree از MaterialApp، Scaffold، AppBar، Center، Column، Text و ElevatedButton تشکیل شده است. هر یک از این ویجت‌ها یک گره در درخت هستند. هنگامی که وضعیت برنامه تغییر می‌کند، Flutter دوباره متد build را فراخوانی کرده و نتیجه را با درخت قبلی مقایسه می‌کند.

ساختار Widget Tree: ویجت‌های ریشه و فرزند

Widget Tree با ویجت ریشه شروع می‌شود که به متد runApp منتقل می‌شود. ویجت ریشه معمولاً MaterialApp، CupertinoApp یا WidgetsApp است » تنظیمات سراسری برنامه را تعیین می‌کند. از ریشه، درخت به ویجت‌های فرزند منشعب می‌شود که هر یک می‌توانند فرزندان خود را داشته باشند.

ویجت‌های تک‌فرزند و چندفرزند

ویجت‌ها در Flutter به single-child (یک فرزند از طریق پارامتر child می‌پذیرند) و multi-child (لیست فرزندان را از طریق children می‌پذیرند) تقسیم می‌شوند. مثال‌های single-child: Center، Padding، SizedBox، Container. Multi-child: Column، Row، Stack، ListView، GridView. این تفاوت بر ساختار Widget Tree تأثیر می‌گذارد: ویجت‌های multi-child درختان عریض‌تر و single-child درختان عمیق‌تری ایجاد می‌کنند.

نقش BuildContext در درخت

BuildContext «موقعیت ویجت در Widget Tree است. هر ویجت BuildContext خود را دارد که به متد build منتقل می‌شود و برای دسترسی به ویجت‌های والد، تم، MediaQuery و سایر InheritedWidget‌ها استفاده می‌شود. BuildContext پلی بین ویجت و عنصر آن در Element Tree است.

dart
class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    final mediaQuery = MediaQuery.of(context);
    return Container(
      color: theme.colorScheme.primary,
      child: Text(
        "عرض صفحه: ${mediaQuery.size.width}"
      ),
    );
  }
}

در این مثال، BuildContext برای دریافت تم و اندازه‌های صفحه استفاده می‌شود. Flutter در Widget Tree به سمت بالاترین Theme و MediaQuery که InheritedWidget هستند، حرکت می‌کند. این نشان می‌دهد که زمینه چگونه ویجت را به موقعیت آن در سلسله‌مراتب متصل می‌کند.

Flutter چگونه Widget Tree را هنگام راه‌اندازی می‌سازد؟

هنگام راه‌اندازی برنامه Flutter، تابع runApp فراخوانی می‌شود که ویجت ریشه را می‌پذیرد و ساخت Widget Tree را آغاز می‌کند. این فرآیند شامل سه مرحله است: ایجاد پیکربندی ویجت‌ها، تشکیل Element Tree و ساخت RenderObject Tree برای ترسیم واقعی.

مرحله 1: ایجاد ویجت ریشه

تابع runApp عنصر ریشه را از طریق WidgetsFlutterBinding ایجاد می‌کند که فریمورک را به موتور گرافیکی متصل می‌کند. ویجت ریشه در درخت قرار می‌گیرد و Flutter متد build را برای پر کردن با ویجت‌های فرزند فراخوانی می‌کند. هر فراخوانی build یک زیرگراف جدید از Widget Tree ایجاد می‌کند.

مرحله 2: layout اولیه

پس از ساخت Widget Tree، Flutter layout اولیه را انجام می‌دهد » محاسبه اندازه‌ها و موقعیت‌های همه ویجت‌ها. این فرآیند از ریشه شروع می‌شود و به سمت پایین درخت گسترش می‌یابد. هر ویجت محدودیت‌هایی را از والد دریافت می‌کند و اندازه محاسبه‌شده را برمی‌گرداند. اگر اندازه‌ها مطابقت نداشته باشند، Flutter خطای layout ایجاد می‌کند.

مرحله 3: ترسیم روی صفحه

پس از اتمام layout، Flutter ترسیم هر ویجت را آغاز می‌کند. RenderObject توصیف رابط را به دستورات گرافیکی تبدیل می‌کند که توسط GPU از طریق Skia یا Impeller اجرا می‌شوند. کل فرآیند » از Widget Tree تا پیکسل‌ها » در هر به‌روزرسانی وضعیت با فرکانس تا 120 فریم در ثانیه تکرار می‌شود.

StatelessWidget و StatefulWidget در سلسله‌مراتب درخت

StatelessWidget «ویجتی است که وضعیت داخلی قابل تغییری ندارد. ظاهر آن کاملاً توسط پارامترهای ورودی که از طریق سازنده منتقل می‌شوند تعیین می‌شود. اگر پارامترها تغییر نکرده باشند، StatelessWidget بازسازی نمی‌شود. این آن را از نظر عملکرد سبک می‌کند.

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

از StatelessWidget برای عناصر ایستا رابط استفاده کنید: آیکون‌ها، برچسب‌های متنی، جداکننده‌های تزئینی و دکمه‌های ساده بدون منطق داخلی. طبق مستندات Flutter، حدود 70٪ از ویجت‌ها در یک برنامه معمولی می‌توانند StatelessWidget باشند که بار جمع‌آوری کننده زباله را کاهش داده و rebuild را سرعت می‌بخشد.

StatefulWidget و مدیریت وضعیت

StatefulWidget یک شی State ایجاد می‌کند که بین بازسازی‌های ویجت حفظ می‌شود. وقتی وضعیت تغییر می‌کند (از طریق فراخوانی setState)، Flutter ویجت را به عنوان “کثیف” علامت‌گذاری کرده و در فریم بعدی آن را بازسازی می‌کند. StatefulWidget امکان پیاده‌سازی عناصر تعاملی را فراهم می‌کند: فیلدهای ورودی، انیمیشن‌ها، تایمرها و لیست‌های پویا.

dart
class CounterWidget extends StatefulWidget {
  @override
  State<CounterWidget> createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
  int _count = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text("تعداد: $_count"),
        ElevatedButton(
          onPressed: () {
            setState(() => _count++);
          },
          child: Text("افزایش"),
        ),
      ],
    );
  }
}

در این مثال، StatefulWidget از setState برای تغییر شمارنده استفاده می‌کند. وقتی وضعیت به‌روزرسانی می‌شود، Flutter فقط بخش تغییر یافته Widget Tree » ویجت CounterWidget و فرزندانش را بازسازی می‌کند. ویجت‌های والد بازسازی نمی‌شوند که این مزیت کلیدی مدل اعلانی Flutter است.

Widget Tree چگونه با Element Tree مرتبط است

Widget Tree لایه پیکربندی است و Element Tree حلقه واسط بین ویجت‌ها و ترسیم واقعی است. هر ویجت در Widget Tree یک عنصر در Element Tree ایجاد می‌کند که ارجاعی به ویجت ذخیره کرده و چرخه حیات را مدیریت می‌کند. این معماری به Flutter اجازه می‌دهد تغییرات را به طور مؤثر پردازش کند.

ایجاد عنصر از ویجت

هنگامی که Flutter برای اولین بار با یک ویجت روبرو می‌شود، متد createElement را فراخوانی می‌کند که عنصر مربوطه را ایجاد می‌کند. برای StatelessWidget، StatelessElement ایجاد می‌شود؛ برای StatefulWidget، StatefulElement که شی State را نیز ایجاد می‌کند. عنصر حتی اگر ویجت بازآفرینی شود، بین چرخه‌های rebuild حفظ می‌شود.

مکانیزم Keys در Element Tree

Key «شناسه‌ای است که به Flutter کمک می‌کند ویجت‌ها را از Widget Tree قدیم و جدید مطابقت دهد. اگر ویجت دارای Key باشد، Flutter از آن برای یافتن عنصر مربوطه استفاده می‌کند، نه موقعیت در درخت. کلیدها هنگام کار با لیست‌های پویا که ترتیب عناصر ممکن است تغییر کند، ضروری هستند.

dart
ListView(
  children: items.map((item) => ListItem(
    key: ValueKey(item.id),
    data: item,
  )).toList(),
)

بدون Key، Flutter عناصر را بر اساس موقعیت مطابقت می‌دهد که می‌تواند هنگام تغییر ترتیب، به حفظ نادرست وضعیت منجر شود. ValueKey با شناسه یکتا تضمین می‌کند که هر عنصر وضعیت خود را بدون توجه به موقعیت در لیست حفظ کند.

تأثیر Widget Tree بر عملکرد

ساختار Widget Tree به‌طور مستقیم بر عملکرد برنامه Flutter تأثیر می‌گذارد. درختان عمیق با تعداد زیادی ویجت تودرتو زمان بیشتری برای فاز layout نیاز دارند و مصرف حافظه را افزایش می‌دهند. Flutter DevTools ابزارهایی برای تحلیل Widget Tree و شناسایی تنگناها فراهم می‌کند.

تودرتو بودن بیش ازحد

هر سطح تودرتو محاسبات اضافی در layout و paint اضافه می‌کند. به جای تودرتوی عمیق زنجیره‌ای از ساختارهای مسطح‌تر استفاده کنید. برای مثال، Row با Expanded می‌تواند چندین Container تودرتو با Align را جایگزین کند. بر اساس داده‌های Flutter Team، بهینه‌سازی درخت می‌تواند زمان layout را تا 40٪ کاهش دهد.

  • Layout «هر والد محدودیت‌ها را به ویجت‌های فرزند منتقل کرده و اندازه‌ها را دریافت می‌کند که در تودرتوی عمیق زنجیره محاسبات ایجاد می‌کند.
  • Paint «هر ویجت می‌تواند یک لایه جداگانه برای ترسیم ایجاد کند و تودرتوی بیش ازحد تعداد لایه‌ها را افزایش می‌دهد.
  • Memory «هر عنصر در Element Tree حافظه اشغال می‌کند و ویجت‌های اضافی مصرف منابع را افزایش می‌دهند.

ابزارهای تحلیل Widget Tree

Flutter DevTools ویجت “Widget Inspector” را فراهم می‌کند که Widget Tree فعلی را در زمان واقعی نشان می‌دهد. توسعه‌دهنده می‌تواند هر ویجتی را روی صفحه انتخاب کرده و مکان آن را در درخت، پارامترها و محدودیت‌های layout ببیند. این به شناسایی تودرتوی غیرمنتظره، rebuildهای اضافی و مشکلات اندازه کمک می‌کند.

RepaintBoundary برای بهینه‌سازی

RepaintBoundary «ویجتی است که بخشی از Widget Tree را برای ترسیم مستقل جدا می‌کند. اگر محتوای RepaintBoundary تغییر کند، فقط ناحیه آن دوباره ترسیم می‌شود، نه کل صفحه. از RepaintBoundary برای انیمیشن‌ها، لیست‌ها و سایر عناصر مکرراً به‌روزرسانی‌شونده استفاده کنید.

dart
RepaintBoundary(
  child: CustomPaint(
    painter: MyPainter(),
    child: SizedBox(
      width: 200,
      height: 200,
    ),
  ),
)

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

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

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

Widget Tree «توصیف اعلانی رابط است که در هر rebuild بازآفرینی می‌شود. Element Tree بین به‌روزرسانی‌ها حفظ می‌شود و چرخه حیات، وضعیت و مطابقت ویجت‌ها با RenderObject واقعی را مدیریت می‌کند.

چند ویجت می‌تواند در Widget Tree باشد؟

محدودیتی برای تعداد ویجت‌ها وجود ندارد، اما در عمل درختی با هزاران ویجت می‌تواند فاز layout را کند کند. Flutter برای درختان تا چند هزار گره بهینه شده است؛ در تعداد بیشتر، مجازی‌سازی از طریق ListView.builder توصیه می‌شود.

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

از Flutter DevTools » برگه “Widget Inspector” استفاده کنید. برنامه را در حالت debug اجرا کنید، DevTools را در مرورگر باز کنید و هر ویجتی را روی صفحه انتخاب کنید تا مکان آن را در Widget Tree ببینید.

rebuild Widget Tree چیست؟

Rebuild «فرآیند بازآفرینی پیکربندی ویجت‌ها هنگام تغییر وضعیت است. Flutter دوباره متد build را برای ویجت‌های تغییر یافته فراخوانی می‌کند، Widget Tree جدید را با قبلی مقایسه کرده و حداقل تغییرات را به Element Tree اعمال می‌کند.

چگونه Widget Tree را بهینه کنیم؟

عمق تودرتو را کاهش دهید، از ویجت‌های const برای عناصر ایستا استفاده کنید، RepaintBoundary را برای جداسازی انیمیشن‌ها به کار ببرید و از StatefulWidget اضافی در جایی که StatelessWidget کافی است خودداری کنید.

خلاصه

  • Widget Tree «توصیف سلسله‌مراتبی اعلانی UI در Flutter که هر گره یک ویجت با پیکربندی و پارامترها است.
  • Flutter Widget Tree را هنگام راه‌اندازی از طریق runApp می‌سازد و سه مرحله را انجام می‌دهد: ایجاد ویجت ریشه، layout و ترسیم.
  • StatelessWidget وضعیتی ندارد و فقط هنگام تغییر پارامترهای ورودی بازسازی می‌شود؛ StatefulWidget از setState برای مدیریت داده‌های پویا استفاده می‌کند.
  • Element Tree بین بازسازی‌ها حفظ می‌شود و Widget Tree را از طریق عناصر به RenderObject Tree متصل می‌کند.
  • کلیدها (Key) مطابقت صحیح ویجت‌ها را هنگام بازسازی تضمین می‌کنند، به‌ویژه در لیست‌های پویا.
  • عمق درخت بر عملکرد تأثیر می‌گذارد » تودرتوی بیش ازحد زمان layout و مصرف حافظه را افزایش می‌دهد.
  • RepaintBoundary بخشی از Widget Tree را برای ترسیم مجدد محلی جدا می‌کند و بار GPU را در انیمیشن‌ها کاهش می‌دهد.

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

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

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

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