Menu
CoddyTech

Sổ tay công thức nấu ăn: Mục yêu thích

Thuộc phần Danh sách và màn hình trong hành trình Flutter của Coddy. Bài học 31 trên 33.

Có những công thức bạn nấu mỗi tuần. Một trái tim ở cuối mỗi hàng đánh dấu công thức yêu thích: trái tim rỗng nếu không phải món yêu thích, trái tim tô đỏ nếu là món yêu thích.

Việc một công thức có phải món yêu thích hay không là một phần của công thức, nên nó trở thành một trường. Khác với các trường khác, nó có thể thay đổi, nên không phải là final, và ban đầu có giá trị false:

bool favorite = false;

Dữ liệu có thể thay đổi cần dùng setState, vì vậy HomeScreen trở thành một StatefulWidget. Các công thức được chuyển ra khỏi build và đặt vào lớp State: danh sách được tạo bên trong build sẽ được tạo lại sau mỗi lần gọi setState, khiến mọi trái tim đều trở về trạng thái rỗng.

Trái tim là một IconButton. Biểu tượng của nó chọn trái tim tô kín hoặc trái tim rỗng bằng ? :, và khi nhấn nút, trường này sẽ đổi giá trị: recipe.favorite = !recipe.favorite.

challenge icon

Thử thách

Khó

Thêm biểu tượng trái tim yêu thích cho mỗi công thức:

  • thêm trường bool favorite = false; vào Recipe
  • chuyển HomeScreen thành StatefulWidget và chuyển danh sách công thức vào lớp State của nó
  • thêm IconButton vào trailing: của mỗi ô, hiển thị Icons.favorite_border hoặc Icons.favorite màu đỏ khi công thức đó được yêu thích. Nhấn vào nút sẽ đảo trạng thái favorite

Tự làm thử

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 StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    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']),
    ];
    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)),
              );
            },
          );
        },
      ),
    );
  }
}

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;

  Recipe({required this.name, required this.minutes, required this.ingredients});
}
quiz iconTự kiểm tra

Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.

Tất cả bài học trong Danh sách và màn hình

Tự luyện tập: Trình biên dịch Flutter online