How to remove list item in Flutter, E Com App 14

Suppose users have added a few items to the cart. But how will they remove a list item in Flutter by dragging them? 

In flutter we can dismiss a list item by dragging in the indicated direction.

When we drag this list item widget in the DismissDirection, it causes the child to slide out of view.

The mechanism is not simple though. The Dismissible widget animates its height, or width to zero over the resizeDuration. It happens when the resizeDuration is non-null.

Finally when its size is zero, it calls onDismissed callback. On the other hand, when the resizeDuration is null, it removes the list item when the animation is complete.

What we just said, is a complex process that takes place when we remove a list item in flutter.

Let’s make it simple. 

In the previous section we have seen how we can design the Cart. 

As a result, when the user adds any item to the list, the number increases.

Before that we have added a Cart Model. However, to nest a new Provider model class, we need to use the multi provider property of the Provider package.

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(
          create: (_) => Products(),
        ),
        ChangeNotifierProvider(
          create: (context) => CartModel(),
        )
      ],
      child: DynamicColorBuilder(
        builder: (lightDynamic, darkDynamic) => ThemeProvider(
          lightDynamic: lightDynamic,
          darkDynamic: darkDynamic,
          settings: settings,
          child: const MyApp(),
        ),
      ),
    ),
  );
}

The advantage of the nested provider in Flutter works in many ways.

To make it happen we have changed our app entry point, that is the main dart file.

Let’s try to understand the workflow. 

In the product overview screen we have a child widget which is the Consumer of the Cart Model class.

...
Consumer<CartModel>(
            builder: (_, cart, child) => CartDesignController(
              value: cart.itemCount.toString(),
              color: Theme.of(context).colorScheme.background,
              child: child,
            ),
            child: IconButton(
              icon: const Icon(
                Icons.shopping_cart,
              ),
              onPressed: () {
                Navigator.of(context).pushNamed(CartScreen.routeName);
              },
            ),
          ),
...

As an outcome, when the user presses the cart icon, we get the list of items. We navigate to the page.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:e_commerce_app/models/cart_model.dart';

import '../controllers/cart_item.dart';

class CartScreen extends StatelessWidget {
  static const routeName = '/cart';

  const CartScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final cart = Provider.of<CartModel>(context);
    return Scaffold(
      appBar: AppBar(
        title: const Text('Your Cart'),
      ),
      body: Column(
        children: <Widget>[
          Card(
            margin: const EdgeInsets.all(15),
            child: Padding(
              padding: const EdgeInsets.all(8),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: <Widget>[
                  const Text(
                    'Total',
                    style: TextStyle(fontSize: 20),
                  ),
                  const Spacer(),
                  Chip(
                    label: Text(
                      '\$${cart.itemCount}',
                      style: TextStyle(
                        color: Theme.of(context).colorScheme.error,
                      ),
                    ),
                    backgroundColor: Theme.of(context).primaryColor,
                  ),
                  TextButton(
                    child: Text(
                      'ORDER NOW',
                      style: TextStyle(
                        color: Theme.of(context).colorScheme.outline,
                      ),
                    ),
                    onPressed: () {},
                  )
                ],
              ),
            ),
          ),
          const SizedBox(height: 10),
          Expanded(
            child: ListView.builder(
              itemCount: cart.items.length,
              itemBuilder: (ctx, i) => CartItem(
                cart.items.values.toList()[i].id,
                cart.items.keys.toList()[i],
                cart.items.values.toList()[i].price,
                cart.items.values.toList()[i].quantity,
                cart.items.values.toList()[i].title,
              ),
            ),
          )
        ],
      ),
    );
  }
}

As a result, we see all the items in one place.

Not only that, users can place their orders here.

Although we’ll discuss this later.

Cart page where order can be placed
Cart page where order can be placed

Removing List items

However, to get all the items is not the only challenge that we face. Users should be able to dismiss or remove any  item from the list. Right? 

To make it happen, we have used the Dismissible widget.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:e_commerce_app/models/cart_model.dart';

class CartItem extends StatelessWidget {
  final String id;
  final String productId;
  final double price;
  final int quantity;
  final String title;

  const CartItem(
    this.id,
    this.productId,
    this.price,
    this.quantity,
    this.title,
  );

  @override
  Widget build(BuildContext context) {
    return Dismissible(
      key: ValueKey(id),
      background: Container(
        color: Theme.of(context).errorColor,
        alignment: Alignment.centerRight,
        padding: const EdgeInsets.only(right: 20),
        margin: const EdgeInsets.symmetric(
          horizontal: 15,
          vertical: 4,
        ),
        child: const Icon(
          Icons.delete,
          color: Colors.white,
          size: 40,
        ),
      ),
      direction: DismissDirection.endToStart,
      onDismissed: (direction) {
        Provider.of<CartModel>(context, listen: false).removeItem(productId);
      },
      child: Card(
        margin: const EdgeInsets.symmetric(
          horizontal: 15,
          vertical: 4,
        ),
        child: Padding(
          padding: const EdgeInsets.all(8),
          child: ListTile(
            leading: CircleAvatar(
              child: Padding(
                padding: const EdgeInsets.all(5),
                child: FittedBox(
                  child: Text('\$$price'),
                ),
              ),
            ),
            title: Text(title),
            subtitle: Text('Total: \$${(price * quantity)}'),
            trailing: Text('$quantity x'),
          ),
        ),
      ),
    );
  }
}

Now it looks simple. Because we have made the ends meet at last.

In the next section, we will see how we can proceed to make the process of ordering completed.

For the full code for this branch please visit the respective GitHub Repository.

What Next?

Books at Leanpub

Books in Apress

My books at Amazon

Courses at Educative

GitHub repository

Python and Data Science

Twitter

Comments

Leave a Reply