Flutter Widgets — ما هو، شجرة القطع و build

المؤلف: IT Sectr نُشر: 2026-02-21 وقت القراءة: 8 دق

Flutter Widgets — اللبنات الأساسية لواجهة المستخدم في إطار Google Flutter، الذي صدر في النسخة المستقرة 1.0 في ديسمبر 2018. في Flutter، كل شيء هو قطعة: من الشاشات والأزرار إلى الهوامش والمحاذاة. تشكل القطع شجرة (widget tree) يقوم Flutter بعرضها على محرك Skia/Impeller الخاص به، متجاوزًا المكونات الأصلية للمنصة. وفقًا لـ Google I/O (2025)، يُستخدم Flutter في أكثر من 500,000 تطبيق على Google Play و App Store. تقسم بنية Flutter القطع إلى StatelessWidget (غير قابلة للتغيير) و StatefulWidget (بحالة قابلة للتغيير عبر كائن State).

النقاط الرئيسية

  • Flutter Widgets — جميع عناصر واجهة المستخدم في Flutter: من الشاشات والأزرار إلى الهوامش والمحاذاة؛ الإطار لا يستخدم المكونات الأصلية للمنصة.
  • StatelessWidget — قطعة بدون حالة قابلة للتغيير؛ تعرض البيانات الممررة عبر المنشئ ولا تتغير بعد البناء (build).
  • StatefulWidget — قطعة بحالة قابلة للتغيير مخزنة في كائن State منفصل يبقى بعد عمليات إعادة البناء.
  • شجرة القطع (widget tree) — تسلسل هرمي للقطع يصف واجهة المستخدم؛ يحوله Flutter إلى Element Tree و Render Tree للعرض.
  • BuildContext — سياق البناء الذي يوفر الوصول إلى موقع القطعة في الشجرة والسمة و MediaQuery و InheritedWidget.

ما هي Flutter Widgets؟

Flutter Widgets — جميع عناصر واجهة المستخدم في إطار Flutter، المنفذة كفئات Dart غير قابلة للتغيير. القطعة هي تكوين عنصر واجهة المستخدم: حجمها ولونها وموضعها ومعالجات الأحداث. على عكس Android (XML + View) أو iOS (Storyboard + UIView)، لا يستخدم Flutter المكونات الأصلية — كل شيء يُرسم بواسطة محرك Skia (Android/iOS/Linux) أو Impeller (iOS/macOS) على Canvas. يضمن هذا مظهرًا متسقًا على جميع المنصات دون اختلافات منصة. يأتي Flutter مع مجموعتين من القطع: Material Widgets (تصميم Google Material Design 3 لنظام Android والويب) و Cupertino Widgets (تصميم Apple HIG لنظامي iOS/macOS). يمكن للمطور دمج المجموعتين في تطبيق واحد. كل قطعة لها طريقة build() تعيد قطعة فرعية أو تركيبًا منها — هكذا تُبنى شجرة القطع.

الأشجار الثلاثة لـ Flutter

يعمل Flutter بثلاث أشجار: Widget Tree (التكوين، ينشئه المطور)، Element Tree (ربط القطعة بموقعها في الشجرة، يديره الإطار) و Render Tree (الكائنات التي تحسب التخطيط وتنفذ الرسم). تنشئ القطعة Element، الذي ينشئ RenderObject. يُعاد استخدام Element عندما يتغير التكوين (rebuild) — هذه آلية تحسين Flutter: إذا تطابق نوع القطعة والمفتاح، لا يُعاد إنشاء Element بل يُحدث بالتكوين الجديد. فهم الأشجار الثلاثة هو مفتاح تحسين أداء تطبيقات Flutter.

StatelessWidget: القطع غير القابلة للتغيير

StatelessWidget — قطعة لا تخزن حالة داخلية. تستقبل معاملات عبر المنشئ وتعرضها دون إمكانية التغيير بعد البناء. StatelessWidget مثالي للعناصر الثابتة: الرؤوس والأيقونات والصور الرمزية والقوائم ذات البيانات الثابتة. تُستدعى طريقة build() مرة واحدة عند الإنشاء وعندما يتغير القطعة الأم. نظرًا لأن StatelessWidget ليس له حالة، فإنه لا يتطلب كائن State منفصل — تُعرف build() مباشرة في فئة القطعة.

dart
import 'package:flutter/material.dart';

class ProfileHeader extends StatelessWidget {
  final String name;
  final String avatarUrl;

  const ProfileHeader({super.key, required this.name, required this.avatarUrl});

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        CircleAvatar(
          radius: 24,
          backgroundImage: NetworkImage(avatarUrl),
        ),
        const SizedBox(width: 12),
        Text(
          name,
          style: const TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.bold,
          ),
        ),
      ],
    );
  }
}

ProfileHeader — StatelessWidget يستقبل name و avatarUrl عبر المنشئ. يعرض CircleAvatar الصورة الرمزية ويعرض Text الاسم. لا يمكن للقطعة تغيير هذه القيم بعد الإنشاء. استخدام منشئ const (const ProfileHeader) يسمح لـ Flutter بإعادة استخدام مثيل القطعة أثناء إعادة بناء القطعة الأم — تحسين دقيق موصى به لجميع StatelessWidget.

StatefulWidget: القطع ذات الحالة

StatefulWidget — قطعة بحالة قابلة للتغيير مخزنة في كائن State منفصل. StatefulWidget نفسه غير قابل للتغيير، مثل StatelessWidget. الجزء القابل للتغيير يُفوض إلى State: State هو كائن يُنشأ مرة واحدة ويبقى عبر عمليات إعادة بناء متعددة للقطعة. عندما تتغير الحالة (setState())، يستدعي Flutter build() على State، محدثًا واجهة المستخدم. يُستخدم StatefulWidget للعناصر التفاعلية: العدادات وحقول النص ومربعات الاختيار والرسوم المتحركة والمؤقتات.

dart
import 'package:flutter/material.dart';

class LikeButton extends StatefulWidget {
  const LikeButton({super.key});

  @override
  State<LikeButton> createState() => _LikeButtonState();
}

class _LikeButtonState extends State<LikeButton> {
  bool liked = false;
  int count = 42;

  void _toggleLike() {
    setState(() {
      liked = !liked;
      count += liked ? 1 : -1;
    });
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: _toggleLike,
      child: Text(liked ? '♥ $count' : '♡ $count'),
    );
  }
}

LikeButton — StatefulWidget مع فئة State _LikeButtonState. الحقلان liked و count هما حالة مخزنة في State ولا يُعاد تعيينهما عند إعادة البناء. setState() يخطر Flutter بأن واجهة المستخدم تحتاج إلى إعادة بناء. لا يعيد Flutter إنشاء State عند كل إعادة بناء للأم — فقط عندما يتغير التكوين (المفتاح أو نوع القطعة). في IT Sectr، نستخدم StatelessWidget للعرض و StatefulWidget للمكونات التفاعلية، متبعين مبدأ تقليل StatefulWidget إلى حدود التغيير.

شجرة القطع: من Widget إلى RenderObject

Widget Tree — هيكل هرمي للقطع يصف واجهة مستخدم التطبيق. يحول Flutter Widget Tree إلى Element Tree: كل قطعة تنشئ Element، الذي يتتبع موقعها في الشجرة واتصالها بـ RenderObject. ينفذ Render Tree التخطيط (تحديد الأحجام والمواضع) والرسم (العرض). Element هو طبقة تحسين رئيسية: إذا لم يتغير نوع القطعة والمفتاح أثناء إعادة البناء، يُعاد استخدام Element، محدثًا التكوين دون إعادة إنشاء RenderObject. يضمن هذا أداء Flutter بمعدلات إطارات عالية (60/120 FPS).

dart
import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('قطع Flutter')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.flutter_dash, size: 80),
            const SizedBox(height: 16),
            const Text(
              'مرحبًا، Flutter!',
              style: TextStyle(fontSize: 24),
            ),
          ],
        ),
      ),
    );
  }
}

شجرة قطع HomeScreen: Scaffold → AppBar + Center → Column → [Icon, SizedBox, Text]. Scaffold هو القطعة الجذرية لتخطيط Material Design. Center توسيط Column التابعة. Column ترتب الأطفال رأسيًا بمحاذاة في الوسط (mainAxisAlignment.center). يحسب Flutter التخطيط من الأعلى للأسفل (تُمرر القيود من الوالد) والأحجام من الأسفل للأعلى (sizedByParent أو sizing from children).

BuildContext: سياق البناء والوصول إلى الشجرة

BuildContext — واصف لموقع القطعة في Element Tree. كل طريقة build() تستقبل BuildContext، يمكن للقطعة من خلاله الوصول إلى: MediaQuery (حجم الشاشة والاتجاه وكثافة البكسل والمنطقة الآمنة)، Theme (MaterialThemeData أو CupertinoThemeData)، Navigator (مكدس التنقل)، ScaffoldMessenger (SnackBar)، InheritedWidget (تمرير البيانات لأسفل الشجرة). لا يجب حفظ BuildContext بعد انتهاء build() أو استخدامه خارج سياق متزامن — يؤدي هذا إلى أخطاء مثل “Scaffold.of() called with a context that does not contain a Scaffold”. بدلاً من حفظ context، استخدم قطعة Builder أو نمط InheritedWidget للوصول إلى البيانات.

Key: تعريف القطعة في الشجرة

Key — معامل اختياري لمنشئ كل قطعة (super.key). يساعد Key Flutter في تعريف القطعة عند تغيير ترتيب أو عدد العناصر في قائمة. بدون Key، يقارن Flutter القطع حسب النوع والموضع؛ عند إضافة عنصر في منتصف قائمة بدون Key، يُعيد Flutter استخدام Element للقطعة الخطأ، مسببًا أخطاء في الحالة (StatefulWidget) ومشاكل في الرسوم المتحركة. استخدم ValueKey (معرف فريد) للقوائم، ObjectKey (بناءً على كائن البيانات)، UniqueKey (مضمون الفريد في كل إعادة بناء — لإعادة الإنشاء القسري).

كتالوج قطع Flutter: Material و Cupertino و Layout

Flutter SDK (النسخة المستقرة 3.3+، Dart 3+) يتضمن أكثر من 200 قطعة مدمجة مقسمة إلى فئات: Layout (Row, Column, Stack, Container, Expanded, Flexible, Wrap, GridView, ListView, CustomScrollView)، Material Design (Scaffold, AppBar, Card, Drawer, BottomNavigationBar, FloatingActionButton, TabBar, Chip, DataTable)، Cupertino (CupertinoPageScaffold, CupertinoNavigationBar, CupertinoButton, CupertinoTabBar)، Painting & Effects (Opacity, DecoratedBox, ClipRect, Transform, BackdropFilter, ShaderMask)، Async (FutureBuilder, StreamBuilder) و Accessibility (Semantics, MergeSemantics, ExcludeSemantics). قطع التخطيط هي أساس أي واجهة Flutter: Row للتسلسلات الأفقية، Column للرأسية، Stack للعناصر المتداخلة، Container مع BoxDecoration للزخرفة.

الفئةالقطع الرئيسيةالغرض
LayoutRow, Column, Stack, Container, Expanded, Flexibleتحديد موضع وأحجام العناصر الفرعية
MaterialScaffold, AppBar, Card, Drawer, FAB, TabBarمكونات واجهة Material Design 3
CupertinoCupertinoPageScaffold, CupertinoNavigationBar, CupertinoButtonمكونات بنمط iOS
PaintingOpacity, ClipRect, Transform, DecoratedBox, BackdropFilterتأثيرات بصرية وقص
AsyncFutureBuilder, StreamBuilderتحميل بيانات غير متزامن مع حالات واجهة
AccessibilitySemantics, MergeSemanticsترميز دلالي لقارئات الشاشة

الأسئلة الشائعة

كيف يختلف StatelessWidget عن StatefulWidget؟

StatelessWidget ليس له حالة داخلية — جميع البيانات تُمرر عبر المنشئ ولا تتغير. يخزن StatefulWidget الحالة القابلة للتغيير في كائن State منفصل يبقى بعد إعادة البناء. تغيير الحالة يستدعي setState()، ويقوم Flutter بإعادة بناء واجهة المستخدم. استخدم StatelessWidget للعناصر غير القابلة للتغيير؛ واستخدم StatefulWidget للعناصر التفاعلية.

ما هو BuildContext في Flutter؟

BuildContext هو واصف لموقع القطعة في Element Tree، يُمرر إلى طريقة build(). من خلال context، تحصل القطعة على الوصول إلى MediaQuery و Theme و Navigator و ScaffoldMessenger و InheritedWidget. لا يجب حفظ BuildContext بعد انتهاء build(). للوصول إلى البيانات، استخدم قطعة Builder أو InheritedWidget.

هل أحتاج إلى معرفة Dart للعمل مع Flutter؟

نعم، يستخدم Flutter Dart كلغة برمجة وحيدة. Dart هي لغة ثابتة الأنواع مع null safety و sound null safety و extension methods و pattern matching. للبدء، يكفي معرفة أساسيات Dart: الفئات والدوال و async/await والمجموعات. يُترجم Dart إلى كود أصلي (AOT) عبر Dart Native وإلى JavaScript (للويب) عبر Dart2JS.

هل Flutter مخصص للمنصات المحمولة فقط؟

لا، يدعم Flutter ست منصات: iOS و Android و Web و macOS و Windows و Linux. أكثر من 90٪ من الكود مشترك بين جميع المنصات. يتم تنفيذ تكييفات المنصة (الكاميرا ونظام الملفات) عبر الإضافات أو قنوات المنصة. لسطح المكتب، يستخدم Flutter غلاف نافذة Flutter Desktop؛ وللويب، يستخدم محرك CanvasKit (WebGL) أو عارض HTML.

كيف يحقق Flutter أداء 60 إطارًا في الثانية؟

يحقق Flutter 60/120 إطارًا في الثانية من خلال: محركه ثنائي الأبعاد (Skia/Impeller)، عدم وجود جسر أصلي (على عكس React Native)، ثلاثة أشجار (Widget → Element → Render) مع إعادة استخدام Element عندما لا يتغير النوع/المفتاح، وخوارزمية تخطيط باتجاه واحد (القيود للأسفل والأحجام للأعلى) و RepaintBoundary لعزل إعادة رسم مناطق فردية من الشاشة.

الملخص

  • Flutter Widgets — جميع عناصر واجهة المستخدم: من Scaffold إلى SizedBox؛ يعرضها Flutter بنفسه على Skia/Impeller، دون استخدام مكونات أصلية.
  • StatelessWidget — قطعة بدون حالة؛ build() تعيد واجهة المستخدم بناءً على معاملات منشئ غير قابلة للتغيير.
  • StatefulWidget — قطعة بحالة قابلة للتغيير في State؛ setState() تؤدي إلى إعادة بناء واجهة المستخدم.
  • ثلاث أشجار Flutter: Widget (تكوين) → Element (موضع) → Render (تخطيط + رسم)؛ يُعاد استخدام Element للأداء.
  • BuildContext — موقع القطعة في الشجرة؛ الوصول إلى MediaQuery و Theme و Navigator و InheritedWidget.
  • Material و Cupertino — مجموعتان من القطع لـ Google Material Design 3 و Apple HIG على التوالي.
  • Key (ValueKey, ObjectKey, UniqueKey) — تعريف القطعة عند تغيير الترتيب أو العدد في قائمة.

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا