Menu
CoddyTech

Giỏ hàng: Màn hình giỏ hàng

Thuộc phần Quản lý trạng thái trong hành trình Flutter của Coddy. Bài học 24 trên 27.

Màn hình thứ hai hiển thị những món có trong giỏ hàng. Đây là một ConsumerWidget theo dõi cùng cartProvider, vì vậy bạn không cần truyền gì vào màn hình này: chỉ cần điều hướng đến đó, màn hình sẽ tự đọc giỏ hàng.

class CartScreen extends ConsumerWidget {
  const CartScreen({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final cart = ref.watch(cartProvider);
    return Scaffold(
      appBar: AppBar(title: const Text('Your cart')),
      body: ...,
    );
  }
}

Bạn còn nhớ provider nằm bên ngoài home mà màn hình được điều hướng đến không thể truy cập không? Điều đó không thể xảy ra ở đây: ProviderScope bao bọc toàn bộ ứng dụng, nên mọi màn hình đều có thể truy cập mọi provider.

Một danh sách trống trên màn hình trông như bị lỗi, vì vậy hãy hiển thị một câu thay thế: cart.isEmpty ? ... : ... chọn giữa hai nội dung.

challenge icon

Thử thách

Trung bình

Tạo màn hình giỏ hàng:

  • Thêm CartScreen ConsumerWidget với tiêu đề Your cart.
  • Màn hình liệt kê từng sản phẩm trong giỏ hàng dưới dạng ListTile, hiển thị tên và giá ở trailing.
  • Khi giỏ hàng trống, màn hình hiển thị Your cart is empty thay thế.
  • Biểu tượng giỏ hàng trên thanh trên cùng của cửa hàng sẽ mở màn hình này.

Tự làm thử

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

class Product {
  const Product(this.name, this.price);

  final String name;
  final double price;
}

const products = [
  Product('Apple', 0.5),
  Product('Bread', 2.25),
  Product('Cheese', 4),
  Product('Milk', 1.2),
];

class Cart extends Notifier<List<Product>> {
  @override
  List<Product> build() => [];

  void add(Product product) {
    state = [...state, product];
  }
}

final cartProvider = NotifierProvider<Cart, List<Product>>(Cart.new);

void main() {
  runApp(const ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: ShopPage(),
    );
  }
}

class ShopPage extends ConsumerWidget {
  const ShopPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final cart = ref.watch(cartProvider);
    return Scaffold(
      appBar: AppBar(
        title: const Text('Shop'),
        actions: [
          IconButton(
            icon: Badge(
              label: Text('${cart.length}'),
              isLabelVisible: cart.isNotEmpty,
              child: const Icon(Icons.shopping_cart),
            ),
            onPressed: () {},
          ),
        ],
      ),
      body: ListView(
        children: [
          for (final product in products)
            ListTile(
              title: Text(product.name),
              subtitle: Text('\$${product.price.toStringAsFixed(2)}'),
              trailing: IconButton(
                icon: const Icon(Icons.add_shopping_cart),
                onPressed: () {
                  ref.read(cartProvider.notifier).add(product);
                },
              ),
            ),
        ],
      ),
    );
  }
}
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 Quản lý trạng thái

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