Row و Column في Flutter: ترتيب العناصر
انظر إلى أي تطبيق على هاتفك: قائمة محادثات فيها صورة ثم اسم ورسالة ثم وقت، وشريط علوي فيه عنوان ثم أيقونات. كل هذه التصميمات مبنية من قطعتين أساسيتين: Row لترتيب العناصر أفقياً، و Column لترتيبها رأسياً. في هذا الدرس ستتقن الاثنين، وتتعلم كيف توزع المساحة بينهما.
Column و Row
Section titled “Column و Row”const Column( children: [ Text('الأول'), Text('الثاني'), Text('الثالث'), ],)Column ترتب أبناءها فوق بعضهم من الأعلى للأسفل. و Row بنفس الصيغة تماماً، لكنها ترتبهم بجانب بعضهم. وفي التطبيق العربي يبدأ Row من اليمين تلقائياً.
تخيّل Column مثل رفوف المكتبة فوق بعضها، و Row مثل الكتب المصفوفة على الرف الواحد.
المحوران
Section titled “المحوران”هذه أهم فكرة في الدرس:
- المحور الرئيسي (Main Axis): اتجاه الترتيب نفسه. في
Rowأفقي، وفيColumnرأسي. - المحور المتقاطع (Cross Axis): الاتجاه العمودي عليه. في
Rowرأسي، وفيColumnأفقي.
ولكل محور خاصية تحاذي العناصر عليه:
const Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('مدرستي', style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold)), Row( children: [ Icon(Icons.search), SizedBox(width: 12), Icon(Icons.notifications), ], ), ],)هذا شريط علوي: العنوان في جهة، والأيقونتان في الجهة الأخرى. و spaceBetween وزعت المساحة الفارغة بينهما.
قيم mainAxisAlignment: start (البداية)، و center، و end، و spaceBetween (الأول والأخير على الأطراف)، و spaceAround، و spaceEvenly (مسافات متساوية تماماً).
قيم crossAxisAlignment: start و center و end، و stretch (تمديد العناصر لتملأ المحور المتقاطع).
Expanded: توزيع المساحة
Section titled “Expanded: توزيع المساحة”ماذا لو أردت ثلاثة صناديق تملأ عرض الشاشة كله؟ لف كل واحد بـ Expanded:
Row( children: [ Expanded(child: _box('HTML', Colors.orange)), const SizedBox(width: 8), Expanded(child: _box('CSS', Colors.blue)), const SizedBox(width: 8), Expanded(flex: 2, child: _box('JavaScript', Colors.amber)), ],)Expandedتعني: «خذ نصيبك من المساحة المتبقية».flex: 2تعني «خذ نصيبين». هنا JavaScript عرضه ضعف كل من HTML و CSS.SizedBox(width: 8)تضع فراغاً ثابتاً بين الصناديق.
تخيّل Expanded مثل تقسيم قطعة أرض بين ورثة: كل واحد له أسهم (flex)، وتُقسم الأرض حسب الأسهم.
والدالة _box دالة مساعدة صغيرة تُرجع صندوقاً ملوناً، كتبناها لنتجنب تكرار نفس الكود ثلاث مرات:
Widget _box(String label, Color color) { return Container( height: 60, alignment: Alignment.center, decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(10)), child: Text(label, style: const TextStyle(color: Colors.white)), );}مثال واقعي: عنصر في قائمة محادثات
Section titled “مثال واقعي: عنصر في قائمة محادثات”const Row( children: [ CircleAvatar(child: Icon(Icons.person)), SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('سارة أحمد', style: TextStyle(fontWeight: FontWeight.bold)), Text('أنهت درس الحلقات اليوم'), ], ), ), Text('10:30'), ],)صورة دائرية، ثم عمود فيه الاسم والرسالة يأخذ كل المساحة المتبقية بفضل Expanded، ثم الوقت في الطرف الآخر. و CrossAxisAlignment.start جعلت النصين يبدآن من نفس الحافة بدلاً من التوسيط.
هذا هو الأسلوب الذي ستبني به أغلب الشاشات: Row داخل Column داخل Row، مثل علب داخل علب.
Stack: العناصر فوق بعضها
Section titled “Stack: العناصر فوق بعضها”أحياناً تحتاج وضع عنصر فوق آخر، مثل شارة «جديد» فوق صورة:
SizedBox( height: 120, child: Stack( children: [ Container(color: Colors.indigo.shade100), const Positioned( top: 8, left: 8, child: Chip(label: Text('جديد')), ), const Center(child: Text('صورة الكورس')), ], ),)Stack ترص أبناءها فوق بعضهم مثل أوراق اللعب: الأول في الأسفل، والأخير في الأعلى. و Positioned تحدد مكان العنصر بالمسافة من الحواف.
خطأ المساحة الشهير: Overflow
Section titled “خطأ المساحة الشهير: Overflow”إذا وضعت في Row عناصر أعرض من الشاشة، سترى شريطاً أصفر وأسود مخططاً على الحافة، ورسالة مثل A RenderFlex overflowed by 42 pixels. معناها: «المحتوى أكبر من المساحة المتاحة».
الحلول:
- لف العنصر الطويل (مثل نص طويل) بـ
Expandedليأخذ المساحة المتاحة فقط وينزل لسطر جديد. - استخدم
WrapبدلRow، فتنتقل العناصر لسطر جديد تلقائياً. - إذا كان المحتوى أطول من الشاشة رأسياً، لف العمود بـ
SingleChildScrollViewليصبح قابلاً للتمرير.
جرّب بنفسك
Section titled “جرّب بنفسك”- ابنِ الشريط العلوي (عنوان وأيقونتان) بـ
RowوspaceBetween. - ابنِ الصناديق الثلاثة بـ
Expanded، وجرّب قيماً مختلفة لـflex. - ابنِ عنصر المحادثة، ثم اكتب رسالة طويلة جداً وتأكد أنها تنزل لسطر جديد بدلاً من الـ Overflow.
- تحدٍّ: صمم بطاقة منتج: صورة (Container ملون) فوقها شارة خصم بـ
Stack، وتحتها صف فيه الاسم والسعر.
أخطاء شائعة
Section titled “أخطاء شائعة”- Overflow في Row: نص طويل بدون
Expanded. لفه بـExpandedأوFlexible. - Expanded خارج Row أو Column:
Expandedتعمل فقط كابن مباشر لـRowأوColumn. - الخلط بين المحورين: في
Columnالمحاذاة الأفقية هيcrossAxisAlignmentوليستmainAxisAlignment.
اختبر نفسك
Section titled “اختبر نفسك”سؤال
في Column، أي خاصية تتحكم في المحاذاة الأفقية للعناصر؟
المحور الرئيسي في Column رأسي، فالأفقي هو المحور المتقاطع ويُضبط بـ crossAxisAlignment.
سؤال
ثلاثة عناصر Expanded في Row، قيم flex لها 1 و 1 و 2. ما نصيب الثالث من المساحة؟
مجموع الأسهم 4، والثالث له سهمان، أي 2 من 4 وهو النصف.
الخلاصة
Section titled “الخلاصة”Columnترتب رأسياً، وRowأفقياً، وفي التطبيق العربي يبدأ الصف من اليمين.mainAxisAlignmentللمحور الرئيسي، وcrossAxisAlignmentللمحور المتقاطع.Expandedتوزع المساحة المتبقية حسبflex، وSizedBoxلفراغ ثابت.StackوPositionedلوضع العناصر فوق بعضها.- خطأ Overflow يعني محتوى أكبر من المساحة، وحله
ExpandedأوWrapأو التمرير.