Покупка товара Flutter Provider
Прошу помочь в реализации данного метода, я новичок в Flutter.
Как это реализовать с помощью Provider
(можно не только Provider, мне главное понять каким образом можно это реализовать и применять на практике)
При нажатии на кнопку купить (в данном случае она у меня одна), передать данные из списка, только "Апельсин" * (если "Мандарин" - то данные "Мандарин")*
При этом, удалять данные из первого экрана в случае нажатии кнопки "Оформить заказ".
List <String> Name = ['Апельсин', 'Мандарин', 'Помидор'];
List <int> Price = [70,60,80];
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Main'),
),
body: ListView.builder(
itemCount: Name.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(left: 10, top: 50, bottom: 50),
child: Text(Name[index].toString()),
),
Row(children: [
Padding(
padding: EdgeInsets.only(left: 100, top: 50, bottom: 50),
child: Text(Price[index].toString()),
),
Padding(
padding: const EdgeInsets.only(left: 100),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(onPressed: (){Navigator.push(context,
CupertinoPageRoute(builder: (context) => const SalePage()));}, child: const
Text('Купить')),
],
),
)
]),
],
),
);
},
),
);
}
}
Ответы (1 шт):
Вот ваши ошибки из-за чего у вас не получилось:
- Работа с двумя списками (
Name
иPrice
), а не со структурой. - Нет общего хранилища.
- Нет понимания как корзина должна работать, как в нее должны попасть данные.
Далее будет рабочий пример как это должно быть и его разбор:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
void main() {
runApp(const MainApp());
}
class Product {
const Product(this.name, this.price);
final String name;
final int price;
}
class Store with ChangeNotifier {
Set<Product> _products = <Product>{
Product('Апельсин', 70),
Product('Мандарин', 60),
Product('Помидор', 80),
};
List<Product> get products => _products.toList();
Product? _cart = null;
Product? get cart => _cart;
void addToCart(Product product) {
_cart = product;
notifyListeners();
}
void removeFromCart(Product product) {
_cart = null;
notifyListeners();
}
void buy() {
_products.remove(_cart);
_cart = null;
notifyListeners();
}
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => Store()),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: MyHomePage(),
),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Main'),
),
body: ListView.builder(
itemCount: context.watch<Store>().products.length,
itemBuilder: (BuildContext context, int index) {
final product = context.watch<Store>().products[index];
return Card(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(left: 10, top: 50, bottom: 50),
child: Text(product.name.toString()),
),
Row(
children: [
Padding(
padding: EdgeInsets.only(left: 100, top: 50, bottom: 50),
child: Text(product.price.toString()),
),
Padding(
padding: const EdgeInsets.only(left: 100),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: () async {
context.read<Store>().addToCart(product);
await Navigator.push(
context,
CupertinoPageRoute(
builder: (context) => const SalePage(),
),
);
context.read<Store>().removeFromCart(product);
},
child: const Text('Купить')),
],
),
)
],
),
],
),
);
},
),
);
}
}
class SalePage extends StatelessWidget {
const SalePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('SalePage'),
),
floatingActionButton: FloatingActionButton(
key: const Key('floatingActionButton'),
onPressed: () => context.read<Store>().buy(),
tooltip: 'Buy',
child: const Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
body: ListView.builder(
itemCount: context.watch<Store>().cart != null ? 1 : 0,
itemBuilder: (BuildContext context, int index) {
return Card(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.only(left: 10, top: 50, bottom: 50),
child: Text(context.watch<Store>().cart!.name.toString()),
),
Row(
children: [
Padding(
padding: EdgeInsets.only(left: 100, top: 50, bottom: 50),
child:
Text(context.watch<Store>().cart!.price.toString()),
)
],
),
],
),
);
},
),
);
}
}
Класс Product
представляет сущность продукта. У него два свойства:
name
— название продукта.price
— цена.
Класс Store
— это главное хранилище состояния приложения. Он реализован с использованием миксина ChangeNotifier
, который позволяет уведомлять виджеты об изменении состояния.
Основные свойства Store
:
_products
: множество продуктов, доступных для покупки._cart
: выбранный продукт, который добавлен в "корзину" для покупки.
Методы Store
:
products
: геттер, возвращающий список продуктов.cart
: геттер, возвращающий текущий продукт в корзине.addToCart(Product product)
: добавляет продукт в корзину.removeFromCart(Product product)
: очищает корзину.buy()
: удаляет продукт из списка доступных продуктов, очищает корзину.
Как работает notifyListeners()
?
Метод notifyListeners()
уведомляет все подписанные виджеты (через Provider
) о том, что состояние хранилища изменилось. Это позволяет автоматически перестроить интерфейс с обновлёнными данными.
Передача Store
через Provider
:
Для доступа к Store
из любого места приложения используется provider
.
Настройка Provider
:
В корне приложения (в MainApp) Store передается через ChangeNotifierProvider:
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => Store()),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: MyHomePage(),
),
)
Теперь любой дочерний виджет может получить доступ к Store с помощью:
context.watch<Store>()
: чтение состояния и автоматическая перестройка при изменении.context.read<Store>()
: чтение состояния без подписки на изменения.
Кстати код почти готов для работы с множеством товаров в корзине, так как изначально эту задачу я сделал так. Если есть желание попрактиковаться, то попробуйте это сделать самостоятельно!