عربة التسوق: إزالة العناصر
جزء من قسم إدارة الحالة في رحلة Flutter على Coddy. الدرس 26 من 27.
يحتاج المتسوق الذي يضيف شيئًا غير صحيح إلى طريقة للتراجع: زر حذف في كل صف من صفوف سلة التسوق.
يمكن أن تحتوي السلة على المنتج نفسه مرتين، لذا احذف حسب الموضع، لا حسب المنتج. تظل القاعدة السابقة سارية: لا تغيّر state في مكانه. أنشئ نسخة، وغيّر النسخة، واجعلها الحالة الجديدة:
void removeAt(int index) {
final copy = [...state];
copy.removeAt(index);
state = copy;
}لمعرفة موضع كل صف، استخدم حلقة مع فهرس: for (var i = 0; i < cart.length; i++)، واستخدم cart[i] للمنتج في ذلك الصف.
احذف عنصرًا وشاهد ما تبقى يتبعه: القائمة، والإجمالي، والشارة عند العودة إلى المتجر. كلها تراقب السلة نفسها.
التحدي
صعبفي شاشة سلة التسوق:
- أضف طريقة
removeAt(int index)إلىCartلتعيين قائمة جديدة لا تحتوي على ذلك العنصر. - انقل سعر كل صف إلى
subtitle، واجعلtrailingعبارة عنIconButtonمعIcons.deleteلإزالة ذلك الصف.
جرّب بنفسك
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);
final totalProvider = Provider((ref) {
final cart = ref.watch(cartProvider);
return cart.fold(0.0, (sum, product) => sum + product.price);
});
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: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const CartScreen()),
);
},
),
],
),
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);
},
),
),
],
),
);
}
}
class CartScreen extends ConsumerWidget {
const CartScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final cart = ref.watch(cartProvider);
final total = ref.watch(totalProvider);
return Scaffold(
appBar: AppBar(title: const Text('Your cart')),
bottomNavigationBar: Padding(
padding: const EdgeInsets.all(24),
child: Text(
'Total: \$${total.toStringAsFixed(2)}',
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
),
body: cart.isEmpty
? const Center(child: Text('Your cart is empty'))
: ListView(
children: [
for (final product in cart)
ListTile(
title: Text(product.name),
trailing: Text('\$${product.price.toStringAsFixed(2)}'),
),
],
),
);
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس إدارة الحالة
2Dart للنماذج
الطرق في الأصناف الخاصة بكالمُعرِّفات في أصنافكاجعل أحد الحقول خاصًااجمع عناصر قائمة باستخدام fold5مشروع: عربة التسوق
عربة التسوق: الإضافة إلى العربةعربة التسوق: شارة العددتدرّب بنفسك: مترجم Flutter عبر الإنترنت