Scaffold و AppBar و Body
فهم ودجة Scaffold
ودجة Scaffold هي واحدة من أهم الودجات في Flutter. توفر البنية البصرية الأساسية لتطبيق Material Design، بما في ذلك أماكن مخصصة لـ شريط التطبيق والمحتوى الرئيسي وزر الإجراء العائم والدرج وشريط التنقل السفلي والورقة السفلية. تقريباً كل شاشة Flutter تبنيها ستستخدم Scaffold كودجة التخطيط الجذرية.
فكر في Scaffold كـ هيكل شاشة تطبيقك. يتعامل مع تحديد مواقع عناصر واجهة المستخدم الشائعة حتى تتمكن من التركيز على المحتوى الفعلي.
بنية Scaffold الأساسية
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('أول Scaffold لي'),
),
body: const Center(
child: Text('مرحباً Scaffold!'),
),
),
);
}
}
تقبل ودجة Scaffold العديد من المعاملات المسماة. إليك الأكثر استخداماً:
appBar-- ودجة تُعرض في أعلى الشاشة، عادةًAppBar.body-- المحتوى الأساسي للشاشة، يُعرض أسفل شريط التطبيق.floatingActionButton-- زر يطفو فوق المحتوى، عادةً للإجراء الأساسي.drawer-- لوحة جانبية تنزلق من اليسار (أو اليمين في RTL).bottomNavigationBar-- شريط تنقل يُعرض في أسفل الشاشة.bottomSheet-- ورقة ثابتة تُعرض في أسفل الشاشة.backgroundColor-- لون خلفية Scaffold بالكامل.
Scaffold مع جميع الخصائص الرئيسية
لنبني مثالاً أكثر اكتمالاً يوضح خصائص Scaffold الرئيسية معاً:
مثال Scaffold كامل
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('الرئيسية'),
backgroundColor: Colors.indigo,
foregroundColor: Colors.white,
),
body: const Center(
child: Text(
'مرحباً بك في التطبيق!',
style: TextStyle(fontSize: 24),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
debugPrint('تم الضغط على FAB!');
},
child: const Icon(Icons.add),
),
floatingActionButtonLocation:
FloatingActionButtonLocation.centerFloat,
backgroundColor: Colors.grey[100],
);
}
}
floatingActionButtonLocation تتيح لك التحكم في مكان وضع FAB. الخيارات تشمل endFloat (الافتراضي، أسفل اليمين)، centerFloat (أسفل الوسط)، endDocked، centerDocked، والمزيد.التعمق في AppBar
ودجة AppBar هي شريط الأدوات المعروض في أعلى الشاشة. هي الودجة الأكثر شيوعاً المستخدمة في خانة appBar في Scaffold. يوفر AppBar مناطق للعنوان وأيقونات التنقل وأزرار الإجراءات.
نظرة عامة على خصائص AppBar
AppBar(
// ودجة العنوان الرئيسية
title: const Text('عنوان التطبيق'),
// ودجة على اليسار (زر الرجوع يُضاف تلقائياً مع Navigator)
leading: IconButton(
icon: const Icon(Icons.menu),
onPressed: () {},
),
// ودجات على الجانب الأيمن
actions: [
IconButton(
icon: const Icon(Icons.search),
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.more_vert),
onPressed: () {},
),
],
// الارتفاع (عمق الظل)
elevation: 4.0,
// الألوان
backgroundColor: Colors.deepPurple,
foregroundColor: Colors.white,
// توسيط العنوان (الافتراضي يختلف حسب المنصة)
centerTitle: true,
)
شرح خصائص AppBar الرئيسية:
title-- الودجة الأساسية المعروضة في شريط التطبيق. عادةً ودجةText، لكن يمكن أن تكون أي ودجة (حقل بحث، شعار، إلخ).leading-- ودجة تُعرض قبل العنوان. إذا كانت null وهناك Drawer، تُضاف أيقونة القائمة تلقائياً. إذا كان المسار الحالي يمكن إرجاعه، يُضاف سهم الرجوع تلقائياً.actions-- قائمة ودجات تُعرض بعد العنوان. عادةً ودجاتIconButtonلإجراءات شريط الأدوات.elevation-- إحداثي z لشريط التطبيق، يتحكم في الظل. اضبطه على0للمظهر المسطح.centerTitle-- هل يتم توسيط العنوان. الافتراضيtrueعلى iOS وfalseعلى Android.flexibleSpace-- ودجة مكدسة خلف شريط الأدوات وشريط التبويبات، مفيدة لتأثيرات الخلفية.toolbarHeight-- ارتفاع منطقة شريط الأدوات (الافتراضيkToolbarHeightوهو 56.0).
AppBar مخصص مع FlexibleSpace
خاصية flexibleSpace تتيح لك وضع ودجة خلف محتوى AppBar. يُستخدم هذا غالباً لخلفيات التدرج أو الصور.
AppBar مع خلفية متدرجة
AppBar(
title: const Text('AppBar متدرج'),
centerTitle: true,
foregroundColor: Colors.white,
flexibleSpace: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [Colors.purple, Colors.deepPurple],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
),
elevation: 0,
)
ودجة PreferredSize
أحياناً تحتاج شريط تطبيق مخصص لا يستخدم ودجة AppBar القياسية. ودجة PreferredSize تخبر Scaffold بارتفاع شريط التطبيق المخصص.
AppBar مخصص مع PreferredSize
Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(80),
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: [Colors.blue, Colors.lightBlueAccent],
),
),
child: const SafeArea(
child: Center(
child: Text(
'شريط تطبيق مخصص',
style: TextStyle(
color: Colors.white,
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
),
),
),
),
body: const Center(
child: Text('محتوى الجسم'),
),
)
PreferredSize عندما تحتاج تحكماً كاملاً في تخطيط شريط التطبيق. غلّف ودجتك المخصصة بـ SafeArea لتجنب التداخل مع شريط حالة الجهاز.أساسيات SliverAppBar
SliverAppBar هو شريط تطبيق متقدم يتكامل مع CustomScrollView لإنشاء تأثيرات قائمة على التمرير مثل الطي والعوم والتثبيت. يُستخدم داخل CustomScrollView بدلاً من خاصية appBar في Scaffold.
SliverAppBar أساسي
class SliverExample extends StatelessWidget {
const SliverExample({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
expandedHeight: 200,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
title: const Text('عرض SliverAppBar'),
background: Image.network(
'https://picsum.photos/800/400',
fit: BoxFit.cover,
),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) => ListTile(
title: Text('العنصر \${index + 1}'),
),
childCount: 30,
),
),
],
),
);
}
}
خصائص SliverAppBar الرئيسية:
expandedHeight-- ارتفاع شريط التطبيق عند التوسع الكامل.floating-- إذا كان true، يظهر شريط التطبيق بمجرد أن يمرر المستخدم للأعلى.pinned-- إذا كان true، يبقى شريط التطبيق مرئياً (مطوياً) في الأعلى عند التمرير للأسفل.snap-- إذا كان true (يتطلبfloating: true)، ينفتح أو ينغلق شريط التطبيق بالكامل.flexibleSpace-- عادةًFlexibleSpaceBarمع عنوان وصورة خلفية.
SliverAppBar داخل CustomScrollView، وليس كخاصية appBar في Scaffold. إذا وضعتها في خانة appBar في Scaffold، ستحصل على خطأ نوع لأن SliverAppBar ليست PreferredSizeWidget.درج Scaffold
خاصية drawer تضيف درج تنقل ينزلق من الحافة اليسرى. عندما يتم توفير درج، يضيف AppBar تلقائياً أيقونة القائمة كودجة leading.
Scaffold مع درج
Scaffold(
appBar: AppBar(
title: const Text('مثال الدرج'),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
const DrawerHeader(
decoration: BoxDecoration(
color: Colors.blue,
),
child: Text(
'قائمة التطبيق',
style: TextStyle(
color: Colors.white,
fontSize: 24,
),
),
),
ListTile(
leading: const Icon(Icons.home),
title: const Text('الرئيسية'),
onTap: () {
Navigator.pop(context);
},
),
ListTile(
leading: const Icon(Icons.settings),
title: const Text('الإعدادات'),
onTap: () {
Navigator.pop(context);
},
),
],
),
),
body: const Center(
child: Text('اسحب من اليسار أو اضغط على أيقونة القائمة'),
),
)
شريط التنقل السفلي في Scaffold
خاصية bottomNavigationBar تضيف شريط تنقل في أسفل الشاشة، يُستخدم عادةً للتبديل بين الأقسام الرئيسية للتطبيق.
مثال شريط التنقل السفلي
class MainScreen extends StatefulWidget {
const MainScreen({super.key});
@override
State<MainScreen> createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
int _selectedIndex = 0;
final List<Widget> _pages = const [
Center(child: Text('الصفحة الرئيسية')),
Center(child: Text('صفحة البحث')),
Center(child: Text('صفحة الملف الشخصي')),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('مثال التنقل السفلي'),
),
body: _pages[_selectedIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedIndex,
onTap: (index) {
setState(() {
_selectedIndex = index;
});
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'الرئيسية',
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'البحث',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'الملف الشخصي',
),
],
),
);
}
}
الورقة السفلية في Scaffold
bottomSheet هي لوحة ثابتة تبقى مرئية في أسفل الشاشة. للأوراق السفلية المشروطة التي تنزلق للأعلى مؤقتاً، استخدم showModalBottomSheet() بدلاً من ذلك.
الورقة السفلية الثابتة مقابل المشروطة
// ورقة سفلية ثابتة (مرئية دائماً)
Scaffold(
appBar: AppBar(title: const Text('الورقة السفلية')),
body: const Center(child: Text('المحتوى الرئيسي')),
bottomSheet: Container(
height: 60,
color: Colors.grey[200],
child: const Center(
child: Text('هذه ورقة سفلية ثابتة'),
),
),
)
// ورقة سفلية مشروطة (تُفعَّل بإجراء المستخدم)
ElevatedButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
height: 200,
padding: const EdgeInsets.all(16),
child: const Column(
children: [
Text(
'ورقة سفلية مشروطة',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 16),
Text('تنزلق للأعلى ويمكن إغلاقها.'),
],
),
);
},
);
},
child: const Text('إظهار الورقة المشروطة'),
)
مثال عملي: هيكل تطبيق كامل
لندمج كل شيء في هيكل تطبيق واقعي يستخدم Scaffold مع AppBar و Drawer و FAB و BottomNavigationBar:
هيكل تطبيق كامل
class AppShell extends StatefulWidget {
const AppShell({super.key});
@override
State<AppShell> createState() => _AppShellState();
}
class _AppShellState extends State<AppShell> {
int _currentIndex = 0;
final List<String> _titles = ['لوحة التحكم', 'المشاريع', 'الرسائل'];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_titles[_currentIndex]),
actions: [
IconButton(
icon: const Icon(Icons.notifications_outlined),
onPressed: () {},
),
],
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
const UserAccountsDrawerHeader(
accountName: Text('أحمد محمد'),
accountEmail: Text('ahmed@example.com'),
currentAccountPicture: CircleAvatar(
child: Text('أ'),
),
),
ListTile(
leading: const Icon(Icons.dashboard),
title: const Text('لوحة التحكم'),
onTap: () => _selectPage(0),
),
ListTile(
leading: const Icon(Icons.folder),
title: const Text('المشاريع'),
onTap: () => _selectPage(1),
),
ListTile(
leading: const Icon(Icons.message),
title: const Text('الرسائل'),
onTap: () => _selectPage(2),
),
const Divider(),
ListTile(
leading: const Icon(Icons.settings),
title: const Text('الإعدادات'),
onTap: () {
Navigator.pop(context);
},
),
],
),
),
body: Center(
child: Text(
'محتوى \${_titles[_currentIndex]}',
style: const TextStyle(fontSize: 24),
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.dashboard),
label: 'لوحة التحكم',
),
BottomNavigationBarItem(
icon: Icon(Icons.folder),
label: 'المشاريع',
),
BottomNavigationBarItem(
icon: Icon(Icons.message),
label: 'الرسائل',
),
],
),
);
}
void _selectPage(int index) {
setState(() {
_currentIndex = index;
});
Navigator.pop(context); // إغلاق الدرج
}
}
UserAccountsDrawerHeader بدلاً من DrawerHeader العادي عندما تريد عرض معلومات الملف الشخصي للمستخدم مع صورة رمزية واسم وبريد إلكتروني. يوفر مظهراً أنيقاً بجهد قليل.تمرين عملي
ابنِ شاشة قائمة على Scaffold بالميزات التالية: (1) AppBar بخلفية متدرجة باستخدام flexibleSpace، وعنوان في المنتصف، وأيقونتي إجراء. (2) درج مع ثلاثة عناصر تنقل على الأقل. (3) محتوى يعرض محتوى مختلفاً بناءً على عنصر الدرج المحدد. (4) FloatingActionButton في موضع centerFloat. التحدي: أضف BottomNavigationBar بثلاث تبويبات وزامنها مع تنقل الدرج.