Menu
CoddyTech

Livre de recettes : Pas encore de favoris

Fait partie de la section Listes et écrans du Journey Flutter de Coddy. Leçon 33 sur 33.

Ouvre l’onglet Favoris avant d’ajouter quoi que ce soit aux favoris : l’écran est vide, et un écran vide semble cassé. Une liste vide devrait indiquer pourquoi elle est vide.

La propriété isEmpty d’une liste vaut true lorsqu’elle ne contient aucun élément. Choisis la page dans build avec un if, avant le return :

Widget page;
if (index == 0) {
  page = recipeList(recipes);
} else if (favorites.isEmpty) {
  page = const Center(child: Text('No favorites yet'));
} else {
  page = recipeList(favorites);
}

Une variable de type Widget peut contenir n’importe quel widget, donc page est une liste dans une branche et un message dans l’autre. Le corps du Scaffold est alors page.

challenge icon

Défi

Facile

Lorsque l’onglet Favorites n’a rien à afficher, affichez No favorites yet au milieu de l’écran, en taille 18, à la place de la liste vide. Une fois qu’une recette est marquée comme favorite, l’onglet l’affiche de nouveau.

Essayez vous-même

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']),
  ];
  int index = 0;

  Widget recipeList(List<Recipe> shown) {
    return ListView.builder(
      itemCount: shown.length,
      itemBuilder: (context, i) {
        final Recipe recipe = shown[i];
        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;
              });
            },
          ),
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    final List<Recipe> favorites = recipes.where((recipe) => recipe.favorite).toList();
    return Scaffold(
      appBar: AppBar(title: const Text('Recipe Book')),
      body: index == 0 ? recipeList(recipes) : recipeList(favorites),
      bottomNavigationBar: NavigationBar(
        selectedIndex: index,
        onDestinationSelected: (int i) {
          setState(() {
            index = i;
          });
        },
        destinations: const [
          NavigationDestination(
            icon: Icon(Icons.menu_book_outlined),
            selectedIcon: Icon(Icons.menu_book),
            label: 'Recipes',
          ),
          NavigationDestination(
            icon: Icon(Icons.star_border),
            selectedIcon: Icon(Icons.star),
            label: 'Favorites',
          ),
        ],
      ),
    );
  }
}

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});
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Listes et écrans

Entraînez-vous par vous-même : Compilateur Flutter en ligne