الـ Widgets الأساسية في Flutter
تعلمت أن كل شيء في Flutter Widget، وأن الشاشة شجرة من الـ Widgets داخل بعضها. في هذا الدرس ستتعرف على القطع الأساسية التي ستستخدمها في كل شاشة تقريباً: النصوص، والصناديق، والمسافات، والأيقونات، والصور. وفي النهاية ستركّبها معاً لتبني بطاقة تعريف شخصية جميلة.
Text: عرض النصوص
Section titled “Text: عرض النصوص”const Text( 'سارة أحمد', style: TextStyle( fontSize: 22, fontWeight: FontWeight.bold, color: Colors.indigo, ),)- المعامل الأول (بالموضع) هو النص نفسه.
styleيستقبلTextStyleفيه:fontSizeللحجم، وfontWeightللسمك، وcolorللون.textAlign: TextAlign.centerلتوسيط النص إذا امتد على أكثر من سطر.
لاحظ أن الأسلوب يشبه CSS كثيراً، لكنه مكتوب بـ Dart وبمعاملات مسماة.
Container: الصندوق متعدد المواهب
Section titled “Container: الصندوق متعدد المواهب”Container أكثر Widget مرونة: صندوق يمكن أن يكون له حجم ومسافات ولون وإطار وزوايا دائرية:
Container( width: 280, padding: const EdgeInsets.all(20), margin: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.indigo.shade50, borderRadius: BorderRadius.circular(16), border: Border.all(color: Colors.indigo, width: 2), ), child: const Text('محتوى الصندوق'),)padding: مسافة داخلية بين الإطار والمحتوى.margin: مسافة خارجية حول الصندوق.decoration: الشكل: اللون، والزوايا الدائرية، والإطار، وحتى الظل والتدرج.child: الـ Widget الموجود داخل الصندوق.
إذا درست CSS، ستلاحظ أن هذا هو نموذج الصندوق نفسه تقريباً. وإذا لم تدرسه، تخيّل Container مثل علبة هدايا: لها حجم، وورق تغليف ملون، ومسافة بين الهدية وجدار العلبة.
EdgeInsets: تحديد المسافات
Section titled “EdgeInsets: تحديد المسافات”EdgeInsets.all(16) // من كل الجهاتEdgeInsets.symmetric(horizontal: 16, vertical: 8) // أفقي ورأسيEdgeInsets.only(top: 12) // جهة واحدةPadding و SizedBox
Section titled “Padding و SizedBox”إذا احتجت مسافة فقط دون لون أو إطار، فلا داعي لـ Container:
const Padding( padding: EdgeInsets.only(top: 12), child: Text('أحب البرمجة والرسم'),)
const SizedBox(height: 12) // فراغ رأسي بين عنصرينSizedBox بدون child هي أبسط طريقة لوضع فراغ بين عنصرين، وستستخدمها كثيراً جداً.
الأيقونات
Section titled “الأيقونات”const Icon(Icons.account_circle, size: 72, color: Colors.indigo)Icons فيها آلاف أيقونات Material الجاهزة. ابحث عن أي أيقونة باسمها الإنجليزي في موقع Material Icons، أو اكتب Icons. في المحرر واستعرض الاقتراحات.
Image.network('https://dummyjson.com/image/300x200', width: 300)Image.asset('assets/images/logo.png', width: 120)Image.network: صورة من الإنترنت برابطها.Image.asset: صورة من ملفات تطبيقك. لكن يجب أولاً أن تخبر Flutter بمكانها فيpubspec.yaml:
flutter: assets: - assets/images/انتبه للمسافات في بداية الأسطر في ملف pubspec.yaml، فهي جزء من الصيغة، وأي خطأ فيها يمنع ظهور الصور.
Center و Column: لمحة سريعة
Section titled “Center و Column: لمحة سريعة”سترى في المثال القادم Center الذي يضع ابنه في منتصف المساحة المتاحة، و Column الذي يرتب عدة أبناء فوق بعضهم عبر الخاصية children (قائمة وليس ابناً واحداً). سنشرح Column وأخاه Row بالتفصيل في درس قادم.
لاحظ الفرق المهم: أغلب الـ Widgets تأخذ ابناً واحداً في child، والقليل مثل Column و Row تأخذ قائمة في children.
المشروع: بطاقة تعريف شخصية
Section titled “المشروع: بطاقة تعريف شخصية”import 'package:flutter/material.dart';
void main() { runApp(const MaterialApp(home: ProfileCard()));}
class ProfileCard extends StatelessWidget { const ProfileCard({super.key});
@override Widget build(BuildContext context) { return Scaffold( body: Center( child: Container( width: 280, padding: const EdgeInsets.all(20), margin: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.indigo.shade50, borderRadius: BorderRadius.circular(16), border: Border.all(color: Colors.indigo, width: 2), ), child: const Column( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.account_circle, size: 72, color: Colors.indigo), SizedBox(height: 12), Text( 'سارة أحمد', style: TextStyle( fontSize: 22, fontWeight: FontWeight.bold, color: Colors.indigo, ), ), SizedBox(height: 4), Text('مطورة تطبيقات مبتدئة'), Padding( padding: EdgeInsets.only(top: 12), child: Text( 'أحب البرمجة والرسم', textAlign: TextAlign.center, style: TextStyle(color: Colors.black54), ), ), ], ), ), ), ); }}النتيجة: بطاقة بنفسجية فاتحة بإطار وزوايا دائرية في منتصف الشاشة، فيها أيقونة شخص كبيرة، ثم الاسم بخط عريض، ثم الوصف. و mainAxisSize: MainAxisSize.min تجعل العمود بارتفاع محتواه فقط بدلاً من أن يملأ الشاشة.
اقرأ الكود كشجرة: Scaffold ← Center ← Container ← Column ← (أيقونة، مسافة، نص، مسافة، نص، Padding ← نص).
جرّب بنفسك
Section titled “جرّب بنفسك”- شغّل بطاقة التعريف، ثم ضع اسمك ووصفك.
- غيّر لون البطاقة إلى
Colors.teal.shade50والإطار إلىColors.teal. - أضف صفاً من المعلومات تحت الوصف: أيقونة
Icons.location_onونص المدينة (ضعهما مؤقتاً فوق بعضهما). - تحدٍّ: أضف ظلاً للبطاقة بالخاصية
boxShadowداخلBoxDecoration.
أخطاء شائعة
Section titled “أخطاء شائعة”- child مع Column:
Columnتأخذchildren(قائمة)، وليسchild. - color و decoration معاً في Container: يسبب خطأ. ضع اللون داخل
BoxDecoration. - صورة asset لا تظهر: نسيت تسجيل المجلد في
pubspec.yaml، أو أن المسار والاسم لا يطابقان الملف حرفياً.
اختبر نفسك
Section titled “اختبر نفسك”سؤال
ما الفرق بين padding و margin في Container؟
الحشو داخل الصندوق بين الإطار والمحتوى، والهامش خارج الصندوق بينه وبين ما حوله.
سؤال
ما أبسط طريقة لوضع فراغ رأسي 16 بين عنصرين في عمود؟
SizedBox بارتفاع محدد ودون ابن هي الطريقة المعتادة لصنع فراغ بين العناصر.
الخلاصة
Section titled “الخلاصة”TextوTextStyleلعرض النصوص بالحجم والسمك واللون.Containerصندوق بحجم وpaddingوmarginوdecorationللون والزوايا والإطار.PaddingوSizedBoxللمسافات فقط، وEdgeInsetsلتحديدها.Iconمن مكتبةIcons، وImage.networkوImage.assetللصور مع تسجيلها فيpubspec.yaml.- أغلب الـ Widgets تأخذ
childواحداً، وColumnوRowتأخذانchildren.