Widget Tree هي بنية هرمية للعناصر في Flutter تحدد تخطيط واجهة المستخدم. كل عنصر في الواجهة، من زر إلى شاشة كاملة، يمثله عنصر منفصل متداخل داخل حاوية رئيسية. يقوم Flutter بتحديث Widget Tree عند كل تغيير في الحالة — يقارن الإطار الشجرة الجديدة بالقديمة ويطبق الحد الأدنى من التغييرات. وفقًا Flutter Team, 2025، يؤثر هيكل الشجرة الفعال بشكل مباشر على سلاسة الرسوم المتحركة واستجابة الواجهة.
النقاط الرئيسية
Widget Tree هي وصف تعريفي لواجهة المستخدم في Flutter، مبنية على شكل شجرة من العناصر المتداخلة. كل عنصر يحدد جزءًا من واجهة المستخدم: تكوينه، معلمات العرض، وسلوكه عند التفاعل. يصف المطور كيف يجب أن تبدو الواجهة في حالة التطبيق الحالية، ويتولى 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 وغيرها من InheritedWidgets. يعمل 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، وهما من InheritedWidgets. يوضح هذا كيف يربط السياق العنصر بموقعه في التسلسل الهرمي.
عند بدء تشغيل تطبيق Flutter، يتم استدعاء الدالة runApp، التي تأخذ العنصر الجذري وتبدأ في بناء Widget Tree. تتضمن العملية ثلاث مراحل: إنشاء تكوين العناصر، تشكيل Element Tree، وبناء RenderObject Tree للعرض الفعلي.
تنشئ الدالة runApp عنصرًا جذريًا عبر WidgetsFlutterBinding، الذي يربط الإطار بمحرك الرسومات. يتم وضع العنصر الجذري في الشجرة، ويستدعي Flutter طريقة build لملئها بالعناصر التابعة. كل استدعاء لـ build يولد رسمًا بيانيًا فرعيًا جديدًا لـ Widget Tree.
بعد بناء Widget Tree، يقوم Flutter بتنفيذ تخطيط أولي — حساب أحجام ومواقع جميع العناصر. تبدأ هذه العملية من الجذر وتنتشر لأسفل الشجرة. يتلقى كل عنصر قيودًا من العنصر الأم ويعيد حجمًا محسوبًا. إذا لم تتطابق الأحجام، يولد Flutter خطأ في التخطيط.
بعد اكتمال التخطيط، يشرع Flutter في عرض كل عنصر. يحول RenderObject وصف الواجهة إلى أوامر رسومية تنفذها وحدة معالجة الرسومات عبر Skia أو Impeller. تتكرر العملية بأكملها — من Widget Tree إلى البكسلات — عند كل تغيير في الحالة بمعدل يصل إلى 120 إطارًا في الثانية.
StatelessWidget هو عنصر ليس له حالة داخلية قابلة للتغيير. مظهره محدد بالكامل بواسطة معاملات الإدخال الممررة عبر المنشئ. إذا لم تتغير المعاملات، لا يتم إعادة بناء StatelessWidget. هذا يجعله خفيفًا من حيث الأداء.
استخدم StatelessWidget لـ عناصر الواجهة الثابتة: الأيقونات، تسميات النص، الفواصل الزخرفية، والأزرار البسيطة بدون منطق داخلي. وفقًا لوثائق Flutter، حوالي 70% من العناصر في تطبيق نموذجي يمكن أن تكون StatelessWidget، مما يقلل من حمل جامع القمامة ويسرع إعادة البناء.
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. يستمر العنصر بين دورات إعادة البناء، حتى إذا تم إعادة إنشاء العنصر.
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. الأشجار العميقة مع العديد من العناصر المتداخلة تتطلب وقتًا أطول لمرحلة التخطيط وتزيد من استخدام الذاكرة. توفر Flutter DevTools أدوات لتحليل Widget Tree وتحديد الاختناقات.
كل مستوى تداخل يضيف حسابات إضافية أثناء التخطيط والرسم. بدلاً من التداخل العميق المتسلسل، استخدم هياكل أكثر تسطحًا. على سبيل المثال، Row مع Expanded يمكن أن يحل محل عدة Containers متداخلة مع Align. وفقًا لـ Flutter Team، يمكن أن يقلل تحسين الشجرة من وقت التخطيط بنسبة تصل إلى 40%.
Flutter DevTools توفر أداة “Widget Inspector” التي تظهر Widget Tree الحالية في الوقت الفعلي. يمكن للمطور تحديد أي عنصر على الشاشة ورؤية مكانه في الشجرة ومعاملاته وقيود التخطيط. هذا يساعد في تحديد التداخل غير المتوقع وعمليات إعادة البناء المفرطة ومشاكل الأبعاد.
RepaintBoundary هو عنصر يعزل جزءًا من Widget Tree للعرض المستقل. إذا تغير المحتوى داخل RepaintBoundary، يتم إعادة رسم منطقته فقط، وليس الشاشة بأكملها. استخدم RepaintBoundary للرسوم المتحركة والقوائم والعناصر الأخرى التي يتم تحديثها بشكل متكرر.
RepaintBoundary(
child: CustomPaint(
painter: MyPainter(),
child: SizedBox(
width: 200,
height: 200,
),
),
)
في هذا المثال، يعزل RepaintBoundary CustomPaint في منطقة عرض منفصلة. عندما يتم تحديث الرسم المتحرك داخل هذه المنطقة، يتم إعادة رسم عنصر CustomPaint فقط، بينما يبقى باقي الشاشة دون تغيير. هذا مفيد بشكل خاص في الواجهات المعقدة ذات العناصر المتحركة المتعددة.
الأسئلة الشائعة
Widget Tree هي وصف تعريفي للواجهة يتم إعادة إنشائه عند كل إعادة بناء. Element Tree يستمر بين التحديثات ويدير دورة الحياة والحالة ومطابقة العناصر مع RenderObjects الفعلية.
لا يوجد حد لعدد العناصر، ولكن عمليًا شجرة بها آلاف العناصر يمكن أن تبطئ مرحلة التخطيط. Flutter محسّن للأشجار التي تصل إلى عدة آلاف من العقد؛ للأعداد الأكبر، يُوصى باستخدام virtualisation عبر ListView.builder.
استخدم Flutter DevTools — علامة التبويب “Widget Inspector”. قم بتشغيل التطبيق في وضع التصحيح، وافتح DevTools في المتصفح، واختر أي عنصر على الشاشة لعرض مكانه في Widget Tree.
إعادة البناء هي عملية إعادة إنشاء تكوين العناصر عندما تتغير الحالة. يستدعي Flutter طريقة build مرة أخرى للعناصر المتغيرة، ويقارن Widget Tree الجديدة مع السابقة ويطبق الحد الأدنى من التغييرات على Element Tree.
قلل عمق التداخل، استخدم const widgets للعناصر الثابتة، طبق RepaintBoundary لعزل الرسوم المتحركة، وتجنب StatefulWidgets المفرطة حيث يكفي StatelessWidget.
الملخص
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا