تخطَّ إلى المحتوى

التنقل بين الشاشات في Flutter: Navigator

الدرس 7 من 33 · Flutter

نادراً ما يكون التطبيق شاشة واحدة. تضغط على منتج فتنتقل لصفحة تفاصيله، وتضغط «رجوع» فتعود للقائمة. وأحياناً تختار شيئاً في شاشة فيظهر اختيارك في الشاشة السابقة. في هذا الدرس ستتعلم كل هذا باستخدام Navigator، المسؤول عن التنقل في Flutter.

Navigator يرتب الشاشات مثل كومة أطباق: كل شاشة جديدة تُوضع فوق السابقة، والرجوع يرفع الطبق العلوي فتظهر الشاشة التي تحته.

  • push: ضع شاشة جديدة فوق الكومة.
  • pop: ارفع الشاشة العلوية وارجع للسابقة.
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DetailsScreen(courseName: 'Flutter'),
),
);
},
child: const Text('افتح تفاصيل الكورس'),
)
  • Navigator.push: افتح شاشة جديدة.
  • context: موقعنا الحالي في شجرة الـ Widgets، ويحتاجه Navigator ليعرف من أين ننتقل.
  • MaterialPageRoute: طريقة الانتقال بحركة Material المعتادة، و builder دالة تُرجع الشاشة الجديدة.

تمرير البيانات للشاشة الجديدة

Section titled “تمرير البيانات للشاشة الجديدة”

لاحظ DetailsScreen(courseName: 'Flutter'): البيانات تُمرر عبر المُنشئ كأي Widget، تماماً كما تعلمت في درس Stateless:

class DetailsScreen extends StatelessWidget {
final String courseName;
const DetailsScreen({super.key, required this.courseName});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('كورس $courseName')),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('رجوع'),
),
),
);
}
}

عند الضغط، تظهر شاشة جديدة عنوانها «كورس Flutter». و AppBar يضيف زر رجوع تلقائياً في الشريط العلوي، لأنه يعرف أن هناك شاشة تحته. وزرنا «رجوع» يفعل نفس الشيء بـ Navigator.pop. وعلى أندرويد يعمل زر الرجوع في الهاتف نفسه أيضاً.

استقبال نتيجة من الشاشة

Section titled “استقبال نتيجة من الشاشة”

أحياناً تفتح شاشة لتختار منها شيئاً، مثل اختيار لون أو صورة، ثم تريد الاختيار في الشاشة الأولى. pop يمكنه إرجاع قيمة، و push يُرجع Future تنتظره بـ await:

class _HomeScreenState extends State<HomeScreen> {
String _chosenColor = 'لم تختر بعد';
Future<void> _pickColor() async {
final result = await Navigator.push<String>(
context,
MaterialPageRoute(builder: (context) => const ColorScreen()),
);
if (result != null) {
setState(() {
_chosenColor = result;
});
}
}
// ... وفي build:
// ElevatedButton(onPressed: _pickColor, child: const Text('اختر لونك المفضل')),
// Text('لونك: $_chosenColor'),
}

وشاشة الاختيار ترجع اللون مع pop:

class ColorScreen extends StatelessWidget {
const ColorScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('اختر لوناً')),
body: Column(
children: [
for (final color in ['أحمر', 'أخضر', 'أزرق'])
ListTile(
title: Text(color),
onTap: () {
Navigator.pop(context, color);
},
),
],
),
);
}
}

ماذا يحدث:

  1. في البداية تعرض الشاشة الرئيسية «لونك: لم تختر بعد».
  2. الضغط على «اختر لونك المفضل» يفتح شاشة الألوان، و await تنتظر.
  3. عند الضغط على «أزرق»، يرجع Navigator.pop(context, color) القيمة 'أزرق' ويغلق الشاشة.
  4. تكمل _pickColor عملها، فتصبح الشاشة: «لونك: أزرق».

هذا تطبيق مباشر لما تعلمته في درس async و await بكورس Dart! والفحص if (result != null) ضروري، لأن المستخدم قد يرجع بزر الرجوع دون أن يختار شيئاً، فتكون النتيجة null.

لاحظ أيضاً for داخل children: حلقة داخل القائمة تولّد عنصراً لكل لون، وهي «collection for» أخت «collection if».

في التطبيقات الكبيرة يمكنك إعطاء كل شاشة اسماً في MaterialApp:

MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => const HomeScreen(),
'/details': (context) => const DetailsScreen(courseName: 'Dart'),
},
)

ثم تنتقل بالاسم من أي مكان: Navigator.pushNamed(context, '/details'). هذا يشبه المسارات المسماة في مواقع الويب.

بعد تسجيل الدخول بنجاح، لا تريد أن يضغط المستخدم «رجوع» فيعود لشاشة الدخول! استخدم Navigator.pushReplacement بدلاً من push: تفتح الشاشة الجديدة وتحذف الحالية من الكومة.

  1. أنشئ شاشتين: رئيسية وتفاصيل، وانتقل بينهما بـ push و pop.
  2. مرّر اسم الكورس للشاشة الثانية واعرضه في عنوانها.
  3. ابنِ شاشة اختيار الألوان، واعرض اللون المختار في الشاشة الرئيسية.
  4. تحدٍّ: اجعل خلفية الشاشة الرئيسية تتغير فعلاً للون المختار (أرجع Color بدلاً من نص).
  • pop في الشاشة الأولى: لا توجد شاشة تحتها، فقد يظهر شاشة سوداء أو يُغلق التطبيق.
  • نسيان فحص null عند استقبال النتيجة: المستخدم قد يرجع دون اختيار.
  • تمرير البيانات بمتغيرات عامة: مرّرها عبر المُنشئ دائماً، فهذا أوضح وأأمن.

سؤال

أي أمر يغلق الشاشة الحالية ويعود للسابقة مع إرجاع قيمة؟

سؤال

بعد تسجيل الدخول، أي أمر يمنع المستخدم من الرجوع لشاشة الدخول؟

  • Navigator يرتب الشاشات ككومة: push تضيف فوقها، و pop ترفع العلوية.
  • MaterialPageRoute مع builder يحدد الشاشة الجديدة، والبيانات تُمرر عبر المُنشئ.
  • pop(context, value) يرجع نتيجة، و await Navigator.push يستقبلها، مع فحص null.
  • المسارات المسماة في routes و pushNamed، و go_router للتطبيقات الكبيرة.
  • pushReplacement للانتقال بلا رجوع، مثل ما بعد تسجيل الدخول.