עגלת קניות: הסרת פריטים
חלק מהיחידה ניהול מצב במסלול ה-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] עבור המוצר שבאותה שורה.
מוחקים פריט וצופים בשאר מתעדכנים בהתאם: הרשימה, הסכום הכולל, וגם התג בחנות. כולם עוקבים אחר אותה עגלה.
אתגר
קשהבמסך העגלה:
- הוסף ל־
Cartמתודה בשםremoveAt(int index)שמגדירה רשימה חדשה ללא אותו פריט. - העבר את המחיר של כל שורה אל
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 עבור מודלים
מתודות במחלקות שלכםGetters במחלקות שלכםהפכו שדה לפרטיחיבור איברי רשימה באמצעות fold5פרויקט: עגלת קניות
עגלת קניות: הוספה לעגלהעגלת קניות: התגתרגלו בעצמכם: קומפיילר Flutter אונליין