كتاب الوصفات: تبويب المفضلة
جزء من قسم القوائم والشاشات في رحلة Flutter على Coddy. الدرس 32 من 33.
لا تكون القلوب مفيدة إلا إذا استطعت العثور على وصفاتك المفضلة مجددًا. يعرض تبويب ثانٍ، Favorites، الوصفات التي تحمل قلبًا أحمر فقط.
يعرض كلا التبويبين قائمة وصفات تبدو بالطريقة نفسها، لذا اكتب القائمة مرة واحدة، على هيئة دالة تأخذ الوصفات المراد عرضها:
Widget recipeList(List<Recipe> shown) {
return ListView.builder(...);
}الوصفات المفضلة هي الوصفات التي تكون فيها where favorite قيمتها true. حدّدها في أعلى build، لكي يكون التبويب صحيحًا بعد كل setState. ثم يعرض المحتوى recipeList(recipes) أو recipeList(favorites)، حسب التبويب.
التحدي
صعبأضف علامات تبويب إلى دفتر الوصفات:
- انقل
ListView.builderإلى أسلوبWidget recipeList(List<Recipe> shown)الذي يعرض قائمةshown - أضف
NavigationBarبعلامتي تبويب:Recipes(Icons.menu_book_outlinedوIcons.menu_bookعند تحديدها) وFavorites(Icons.star_borderوIcons.starعند تحديدها)، مع الاحتفاظ بـindexعلامة التبويب في الحالة - تعرض علامة التبويب Recipes جميع الوصفات، بينما تعرض علامة التبويب Favorites الوصفات المفضلة فقط
جرّب بنفسك
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final List<Recipe> recipes = [
Recipe(name: 'Pancakes', minutes: 20, ingredients: ['Flour', 'Eggs', 'Milk', 'Butter']),
Recipe(name: 'Tomato Soup', minutes: 35, ingredients: ['Tomatoes', 'Onion', 'Garlic', 'Olive oil']),
Recipe(name: 'Guacamole', minutes: 10, ingredients: ['Avocados', 'Lime', 'Onion', 'Salt']),
Recipe(name: 'Fried Rice', minutes: 25, ingredients: ['Rice', 'Eggs', 'Peas', 'Soy sauce']),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Recipe Book')),
body: ListView.builder(
itemCount: recipes.length,
itemBuilder: (context, index) {
final Recipe recipe = recipes[index];
return ListTile(
leading: const Icon(Icons.restaurant_menu),
title: Text(recipe.name),
subtitle: Text('${recipe.minutes} min'),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => RecipeScreen(recipe: recipe)),
);
},
trailing: IconButton(
icon: Icon(
recipe.favorite ? Icons.favorite : Icons.favorite_border,
color: recipe.favorite ? Colors.red : null,
),
onPressed: () {
setState(() {
recipe.favorite = !recipe.favorite;
});
},
),
);
},
),
);
}
}
class RecipeScreen extends StatelessWidget {
const RecipeScreen({super.key, required this.recipe});
final Recipe recipe;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(recipe.name)),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
Text('Ready in ${recipe.minutes} minutes', style: const TextStyle(fontSize: 18)),
const SizedBox(height: 24),
const Text('Ingredients', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
for (String ingredient in recipe.ingredients)
ListTile(
leading: const Icon(Icons.check_circle_outline),
title: Text(ingredient),
),
],
),
);
}
}
class Recipe {
final String name;
final int minutes;
final List<String> ingredients;
bool favorite = false;
Recipe({required this.name, required this.minutes, required this.ingredients});
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس القوائم والشاشات
1قوائم قابلة للتمرير
قائمة قابلة للتمريرعناصر القائمةالبداية والنهايةاضغط على عنصر قائمةفواصل بين الصفوف4أصنافك الخاصة
صنف لبياناتكالمعاملات المُسمّاة والإلزاميةحقول يمكن أن تكون فارغةعناصر واجهة من البيانات باستخدام mapتصفية قائمة باستخدام whereالبحث في Map7المشروع: كتاب الوصفات
كتاب الوصفات: قائمة الوصفاتكتاب الوصفات: شاشة الوصفة6علامات التبويب والأدراج والتمرير بالسحب
علامات التبويب مع شريط تنقلأيقونات ممتلئة لعلامة التبويب المفتوحةدرج جانبياسحب للحذفالتراجع عن السحبتدرّب بنفسك: مترجم Flutter عبر الإنترنت