Widget Tree «ساختار سلسلهمراتبی ویجتها در Flutter است که ترکیب رابط کاربری را تعیین میکند. هر عنصر رابط، از دکمه گرفته تا کل صفحه، توسط یک ویجت جداگانه که در کانتینر والد قرار گرفته است، نمایش داده میشود. Flutter در هر تغییر وضعیت، Widget Tree را بهروزرسانی میکند » فریمورک درخت جدید و قدیم را مقایسه کرده و حداقل تغییرات را اعمال میکند. بر اساس دادههای Flutter Team, 2025، ساختار مؤثر درخت بهطور مستقیم بر روانی انیمیشنها و سرعت پاسخگویی رابط تأثیر میگذارد.
نکات اصلی
Widget Tree «توصیف اعلانی رابط کاربری در Flutter است که به صورت درختی از ویجتهای تودرتو ساخته شده است. هر ویجت بخشی از UI را تعیین میکند: پیکربندی، پارامترهای نمایش و رفتار آن در هنگام تعامل. توسعهدهنده توصیف میکند که رابط باید در وضعیت فعلی برنامه چگونه به نظر برسد و Flutter مسئول تبدیل این توصیف به پیکسلها روی صفحه است.
برخلاف فریمورکهای امری که توسعهدهنده مستقیماً عناصر رابط را دستکاری میکند، Flutter از رویکرد اعلانی استفاده میکند. با تغییر وضعیت برنامه، یک Widget Tree جدید ایجاد میشود و فریمورک تفاوت بین درخت قدیم و جدید را محاسبه میکند. این کار تعداد عملیات ترسیم را به حداقل میرساند و کد را قابلپیشبینیتر میکند.
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 با ویجت ریشه شروع میشود که به متد 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 «موقعیت ویجت در Widget Tree است. هر ویجت BuildContext خود را دارد که به متد build منتقل میشود و برای دسترسی به ویجتهای والد، تم، MediaQuery و سایر InheritedWidgetها استفاده میشود. BuildContext پلی بین ویجت و عنصر آن در Element Tree است.
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، تابع runApp فراخوانی میشود که ویجت ریشه را میپذیرد و ساخت Widget Tree را آغاز میکند. این فرآیند شامل سه مرحله است: ایجاد پیکربندی ویجتها، تشکیل Element Tree و ساخت RenderObject Tree برای ترسیم واقعی.
تابع runApp عنصر ریشه را از طریق WidgetsFlutterBinding ایجاد میکند که فریمورک را به موتور گرافیکی متصل میکند. ویجت ریشه در درخت قرار میگیرد و Flutter متد build را برای پر کردن با ویجتهای فرزند فراخوانی میکند. هر فراخوانی build یک زیرگراف جدید از Widget Tree ایجاد میکند.
پس از ساخت Widget Tree، Flutter layout اولیه را انجام میدهد » محاسبه اندازهها و موقعیتهای همه ویجتها. این فرآیند از ریشه شروع میشود و به سمت پایین درخت گسترش مییابد. هر ویجت محدودیتهایی را از والد دریافت میکند و اندازه محاسبهشده را برمیگرداند. اگر اندازهها مطابقت نداشته باشند، Flutter خطای layout ایجاد میکند.
پس از اتمام layout، Flutter ترسیم هر ویجت را آغاز میکند. RenderObject توصیف رابط را به دستورات گرافیکی تبدیل میکند که توسط GPU از طریق Skia یا Impeller اجرا میشوند. کل فرآیند » از Widget Tree تا پیکسلها » در هر بهروزرسانی وضعیت با فرکانس تا 120 فریم در ثانیه تکرار میشود.
StatelessWidget «ویجتی است که وضعیت داخلی قابل تغییری ندارد. ظاهر آن کاملاً توسط پارامترهای ورودی که از طریق سازنده منتقل میشوند تعیین میشود. اگر پارامترها تغییر نکرده باشند، StatelessWidget بازسازی نمیشود. این آن را از نظر عملکرد سبک میکند.
از StatelessWidget برای عناصر ایستا رابط استفاده کنید: آیکونها، برچسبهای متنی، جداکنندههای تزئینی و دکمههای ساده بدون منطق داخلی. طبق مستندات Flutter، حدود 70٪ از ویجتها در یک برنامه معمولی میتوانند StatelessWidget باشند که بار جمعآوری کننده زباله را کاهش داده و rebuild را سرعت میبخشد.
StatefulWidget یک شی State ایجاد میکند که بین بازسازیهای ویجت حفظ میشود. وقتی وضعیت تغییر میکند (از طریق فراخوانی setState)، Flutter ویجت را به عنوان “کثیف” علامتگذاری کرده و در فریم بعدی آن را بازسازی میکند. StatefulWidget امکان پیادهسازی عناصر تعاملی را فراهم میکند: فیلدهای ورودی، انیمیشنها، تایمرها و لیستهای پویا.
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 ایجاد میکند که ارجاعی به ویجت ذخیره کرده و چرخه حیات را مدیریت میکند. این معماری به Flutter اجازه میدهد تغییرات را به طور مؤثر پردازش کند.
هنگامی که Flutter برای اولین بار با یک ویجت روبرو میشود، متد createElement را فراخوانی میکند که عنصر مربوطه را ایجاد میکند. برای StatelessWidget، StatelessElement ایجاد میشود؛ برای StatefulWidget، StatefulElement که شی State را نیز ایجاد میکند. عنصر حتی اگر ویجت بازآفرینی شود، بین چرخههای rebuild حفظ میشود.
Key «شناسهای است که به Flutter کمک میکند ویجتها را از Widget Tree قدیم و جدید مطابقت دهد. اگر ویجت دارای Key باشد، Flutter از آن برای یافتن عنصر مربوطه استفاده میکند، نه موقعیت در درخت. کلیدها هنگام کار با لیستهای پویا که ترتیب عناصر ممکن است تغییر کند، ضروری هستند.
ListView(
children: items.map((item) => ListItem(
key: ValueKey(item.id),
data: item,
)).toList(),
)
بدون Key، Flutter عناصر را بر اساس موقعیت مطابقت میدهد که میتواند هنگام تغییر ترتیب، به حفظ نادرست وضعیت منجر شود. ValueKey با شناسه یکتا تضمین میکند که هر عنصر وضعیت خود را بدون توجه به موقعیت در لیست حفظ کند.
ساختار Widget Tree بهطور مستقیم بر عملکرد برنامه Flutter تأثیر میگذارد. درختان عمیق با تعداد زیادی ویجت تودرتو زمان بیشتری برای فاز layout نیاز دارند و مصرف حافظه را افزایش میدهند. Flutter DevTools ابزارهایی برای تحلیل Widget Tree و شناسایی تنگناها فراهم میکند.
هر سطح تودرتو محاسبات اضافی در layout و paint اضافه میکند. به جای تودرتوی عمیق زنجیرهای از ساختارهای مسطحتر استفاده کنید. برای مثال، Row با Expanded میتواند چندین Container تودرتو با Align را جایگزین کند. بر اساس دادههای Flutter Team، بهینهسازی درخت میتواند زمان layout را تا 40٪ کاهش دهد.
Flutter DevTools ویجت “Widget Inspector” را فراهم میکند که Widget Tree فعلی را در زمان واقعی نشان میدهد. توسعهدهنده میتواند هر ویجتی را روی صفحه انتخاب کرده و مکان آن را در درخت، پارامترها و محدودیتهای layout ببیند. این به شناسایی تودرتوی غیرمنتظره، rebuildهای اضافی و مشکلات اندازه کمک میکند.
RepaintBoundary «ویجتی است که بخشی از Widget Tree را برای ترسیم مستقل جدا میکند. اگر محتوای RepaintBoundary تغییر کند، فقط ناحیه آن دوباره ترسیم میشود، نه کل صفحه. از RepaintBoundary برای انیمیشنها، لیستها و سایر عناصر مکرراً بهروزرسانیشونده استفاده کنید.
RepaintBoundary(
child: CustomPaint(
painter: MyPainter(),
child: SizedBox(
width: 200,
height: 200,
),
),
)
در این مثال، RepaintBoundary CustomPaint را در یک ناحیه ترسیم جداگانه ایزوله میکند. هنگام بهروزرسانی انیمیشن در داخل این ناحیه، فقط ویجت CustomPaint دوباره ترسیم میشود و بقیه صفحه بدون تغییر میماند. این بهویژه در رابطهای پیچیده با عناصر انیمیشنی متعدد مفید است.
سؤالات متداول
Widget Tree «توصیف اعلانی رابط است که در هر rebuild بازآفرینی میشود. Element Tree بین بهروزرسانیها حفظ میشود و چرخه حیات، وضعیت و مطابقت ویجتها با RenderObject واقعی را مدیریت میکند.
محدودیتی برای تعداد ویجتها وجود ندارد، اما در عمل درختی با هزاران ویجت میتواند فاز layout را کند کند. Flutter برای درختان تا چند هزار گره بهینه شده است؛ در تعداد بیشتر، مجازیسازی از طریق ListView.builder توصیه میشود.
از Flutter DevTools » برگه “Widget Inspector” استفاده کنید. برنامه را در حالت debug اجرا کنید، DevTools را در مرورگر باز کنید و هر ویجتی را روی صفحه انتخاب کنید تا مکان آن را در Widget Tree ببینید.
Rebuild «فرآیند بازآفرینی پیکربندی ویجتها هنگام تغییر وضعیت است. Flutter دوباره متد build را برای ویجتهای تغییر یافته فراخوانی میکند، Widget Tree جدید را با قبلی مقایسه کرده و حداقل تغییرات را به Element Tree اعمال میکند.
عمق تودرتو را کاهش دهید، از ویجتهای const برای عناصر ایستا استفاده کنید، RepaintBoundary را برای جداسازی انیمیشنها به کار ببرید و از StatefulWidget اضافی در جایی که StatelessWidget کافی است خودداری کنید.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید