Покупка товара 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 шт):

Автор решения: MiT

Вот ваши ошибки из-за чего у вас не получилось:

  1. Работа с двумя списками (Name и Price), а не со структурой.
  2. Нет общего хранилища.
  3. Нет понимания как корзина должна работать, как в нее должны попасть данные.

Далее будет рабочий пример как это должно быть и его разбор:

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>(): чтение состояния без подписки на изменения.

Кстати код почти готов для работы с множеством товаров в корзине, так как изначально эту задачу я сделал так. Если есть желание попрактиковаться, то попробуйте это сделать самостоятельно!

→ Ссылка