SingleChildScrollView

🧱 ما هي SingleChildScrollView؟

SingleChildScrollView هي ويدجت في Flutter تسمح لك بتمرير (Scroll) عنصر واحد فقط عندما يتجاوز حجمه حجم الشاشة.

✅ هي الحل المثالي عندما:

  • لديك محتوى كبير لا يتسع في الشاشة (مثل نموذج طويل).
  • تريد أن تجعل الشاشة قابلة للتمرير عموديًا أو أفقيًا.
  • تضع عنصرًا واحدًا قابلًا للتمرير — عادةً Column.
🔁 الشكل العام:
SingleChildScrollView(
  scrollDirection: Axis.vertical, // أو Axis.horizontal
  child: Widget, // عنصر واحد فقط داخلها
)
Dart
📌 أهم الخصائص (Properties)
1. child

العنصر الوحيد داخل SingleChildScrollView — غالبًا يكون Column, Row, Container, أو أي ويدجت كبيرة.

SingleChildScrollView(
  child: Column(
    children: [
      Text('مرحبا'),
      // ...
    ],
  ),
)
Dart
2. scrollDirection

الاتجاه الذي تريد فيه التمرير

  • Axis.vertical (افتراضي): تمرير عمودي
  • Axis.horizontal: تمرير أفقي
SingleChildScrollView(
  scrollDirection: Axis.horizontal,
  child: Row(...),
)
Dart
3. reverse

إذا كنت تريد أن يبدأ التمرير من النهاية بدلاً من البداية.

SingleChildScrollView(
  reverse: true,
  child: Column(...),
)
Dart

مثال: مفيد في تطبيقات الدردشة بحيث تظهر الرسائل الأخيرة في الأسفل.

4. padding

لإضافة مسافة داخلية حول المحتوى.

SingleChildScrollView(
  padding: EdgeInsets.all(16),
  child: Column(...),
)
Dart
5. physics

تحدد طريقة التمرير (Scroll Behavior)

النوعالتأثير
AlwaysScrollableScrollPhysics()يمكن التمرير دائمًا
NeverScrollableScrollPhysics()يمنع التمرير نهائيًا
BouncingScrollPhysics()يعطي تأثير “نطّ” مثل iOS
ClampingScrollPhysics()يشبه سلوك أندرويد التقليدي

مثال:

SingleChildScrollView(
  physics: BouncingScrollPhysics(),
  child: Column(...),
)
Dart
6. keyboardDismissBehavior

تتحكم في إخفاء لوحة المفاتيح عند التمرير.

القيمةالتأثير
onDragتُخفى عند السحب
manualتحتاج تدخل يدوي

مثال:

SingleChildScrollView(
  keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
  child: Column(...),
)
Dart
🧠 ملاحظات مهمة جدًا:
✅ استخدمها مع Column عندما لا تكفي الشاشة لعرض المحتوى
SingleChildScrollView(
  child: Column(
    children: [
      for (int i = 0; i < 30; i++) Text('عنصر $i'),
    ],
  ),
)
Dart
⚠️ لا تستخدم Expanded داخل Column إذا كانت داخل SingleChildScrollView
// ❌ هذا سيعطيك خطأ!
SingleChildScrollView(
  child: Column(
    children: [
      Expanded(child: Container()), // غير مسموح هنا
    ],
  ),
)
Dart

🛠 الحل:
استخدم SizedBox بارتفاع معين بدلًا من Expanded.

🧪 تمرير أفقي
SingleChildScrollView(
  scrollDirection: Axis.horizontal,
  child: Row(
    children: List.generate(
      20,
      (index) => Container(
        width: 100,
        height: 100,
        color: Colors.primaries[index % Colors.primaries.length],
        margin: EdgeInsets.all(8),
      ),
    ),
  ),
)
Dart
🧰 مثال واقعي لتطبيق يحتوي على Scroll:
@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: Text('تسجيل الدخول')),
    body: SingleChildScrollView(
      padding: EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Text('أهلاً بك!', style: TextStyle(fontSize: 24)),
          SizedBox(height: 20),
          TextField(decoration: InputDecoration(labelText: 'البريد')),
          SizedBox(height: 20),
          TextField(decoration: InputDecoration(labelText: 'كلمة المرور')),
          SizedBox(height: 30),
          ElevatedButton(onPressed: () {}, child: Text('دخول')),
        ],
      ),
    ),
  );
}
Dart
✅ خلاصة
الخاصيةالاستخدام
childعنصر واحد فقط داخل الـ scroll
scrollDirectionاتجاه التمرير
reverseالتمرير من النهاية
physicsنوع التمرير (نط، عادي، منع…)
paddingمسافة داخلية
keyboardDismissBehaviorإخفاء لوحة المفاتيح