mcfred
mcfred

Reputation: 1391

How to manually add items to listview in Flutter

I have a list of cart items which I am displaying using the code below. Right after this list, I would like to display the total amount. This is how the final result should look like:

Chicken Burger 1X $20.5
Chicken Wrap 1X $9.99
Total $30.49

Container(
            padding: EdgeInsets.symmetric(horizontal: 15, vertical: 4),
            height: min(widget.order.products.length * 20.0 + 10, 100),
            child: ListView(
              children: widget.order.products
                  .map(
                    (prod) => Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children: <Widget>[
                             Expanded(child:Text(
                              prod.title,
                              style: TextStyle(
                                fontSize: 16,
                                fontWeight: FontWeight.bold,
                              ),
                            )),
                           Text(
                              '${prod.quantity}x \$. ${prod.price}',
                              style: TextStyle(
                                fontSize: 16,
                                color: Colors.grey,
                              ),
                            )
                          ],          
                        ),
                  )
                  .toList(), 

How can I append total to this list?

Upvotes: 1

Views: 2310

Answers (4)

KuKu
KuKu

Reputation: 7492

Here is my suggestion.

I used spread operator to ListView's children for adding Widget related to 'total'.

Additionally I added one item at Container's height because of Total item in ListView.
Below is summary code that I did.

ListView(
    children: <Widget> [
        ...list.map(...).toList(),
        TotalWidget(),
    ]
)

This is full code based your code.

import 'dart:math';

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: _buildBody(),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          showModalBottomSheet(
            context: context,
            backgroundColor: Colors.blueGrey,
            isScrollControlled: false,
            builder: (context) => Wrap(
              children: [
                ListView.separated(
                  shrinkWrap: true,
                  itemCount: 3,
                  itemBuilder: (BuildContext context, int index) => ListTile(
                    title: Text(
                      'lists[index].listName',
                      style: TextStyle(
                        color: Colors.white,
                      ),
                    ),
                  ),
                  separatorBuilder: (BuildContext context, int index) =>
                      Divider(),
                ),
              ],
            ),
          );
        },
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }

  Widget _buildBody() {
    List<Product> listProduct = [
      Product('Chicken Burger', 1, 20.5),
      Product('Chicken Wrap', 1, 9.99),
    ];
    double totalAmount = 0;
    for (var item in listProduct) {
      totalAmount += (item.price * item.quantity);
    }

    return Container(
      padding: EdgeInsets.symmetric(horizontal: 15, vertical: 4),
      height: min((listProduct.length + 1) * 20.0 + 10, 100),
      child: ListView(
        children: [
          ...listProduct
              .map(
                (prod) => Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: <Widget>[
                    Expanded(
                        child: Text(
                      prod.title,
                      style: TextStyle(
                        fontSize: 16,
                        fontWeight: FontWeight.bold,
                      ),
                    )),
                    Text(
                      '${prod.quantity}x \$. ${prod.price}',
                      style: TextStyle(
                        fontSize: 16,
                        color: Colors.grey,
                      ),
                    )
                  ],
                ),
              )
              .toList(),
          Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Expanded(
                    child: Text(
                  'Total',
                  style: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.bold,
                  ),
                )),
                Text(
                  '$totalAmount',
                  style: TextStyle(
                    fontSize: 16,
                    color: Colors.grey,
                  ),
                )
              ])
        ],
      ),
    );
  }
}

class Product {
  String title;
  int quantity;
  double price;

  Product(this.title, this.quantity, this.price);
}

enter image description here

Upvotes: 1

CoderUni
CoderUni

Reputation: 6134

For that, you'd have to learn state management. To make things simple we'll use the built-in StreamBuilder to provide the data. Its best practice to separate your ui from your business logic so I'll do it here.

In order to use a StreamBuilder, you'd have to provide it a Stream<T> where T is your variable's type. In your case, its a List<String>. Lets write it in another file that holds all your buisness logic.

product_bloc.dart:

class ProductBloc {
  final List<String> _productList = ["Item One", "Item Two"];
  StreamController<List<String>> _products = StreamController<List<String>>();
  Stream<List<String>> get products => _products.stream;

  ProductBloc() {
    _products.add(_productList);
  }

  void addProductAfterDelay() async {
    _productList.add("Item Three");
    await Future.delayed(const Duration(seconds: 3));
    _products.add(_productList);
  }
}

product_screen.dart:

StreamBuilder<List<String>>(
  initialData: [],
  builder: (context, snapshot) {
    return ListView.builder(
      itemCount: snapshot.data.length,
      itemBuilder: (context, index) {
      return Text(snapshot.data[index]);
    });
  },
);

Upvotes: 1

Frozen Forest
Frozen Forest

Reputation: 72

If you want add items to ListView, first you have to add those items to your List (for example order.products or new one) and then use state management approach to re render ListView. if your logic is simple you can use stateful widget.

example code:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: MyList(),
      ),
    );
  }
}

class MyList extends StatefulWidget {
  @override
  _MyListState createState() => _MyListState();
}

class _MyListState extends State<MyList> {
  List<String> orders = ["order1", "order2", "order3"];

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Expanded(
          child: ListView(
            children: orders
                .map(
                  (String e) => Card(
                    child: ListTile(
                      title: Text(e),
                    ),
                  ),
                )
                .toList(),
          ),
        ),
        TextButton(
          onPressed: () {
            List<String> extraFields = ["field1", "field2"];
            setState(
              () {
                orders.addAll(extraFields);
              },
            );
          },
          child: Text("Add extra fields"),
        ),
      ],
    );
  }
}

Upvotes: 1

Huthaifa Muayyad
Huthaifa Muayyad

Reputation: 12353

Edit 1, after op updated more info in comments:

Column(children: [  Text(widget.order.totalPrice.toString()),
Flexible(child:
ListView(
children: 
  widget.order.products
 .map((prod) => Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, 
  children: <Widget>[
  Expanded(child:Text(
  prod.title,
  style: TextStyle(
  fontSize: 16,
  fontWeight: FontWeight.bold,
   ),
  )),
 Text(
 '${prod.quantity}x \$. ${prod.price}',
   style: TextStyle(
     fontSize: 16,
   color: Colors.grey,
    ),
   )
  ],          
 ),
)
.toList())]), 

Since total isn't being stored as a single variable your list\cart object. You need to create a double totalPrice = 0.0;

then use a forLoop to add the values

for (var prod in widget.order.products) {
totalPrice += (prod.price * prod.quantity);}

Display this totalPrice wherever you want, you can't have it in the listView though.

Upvotes: 1

Related Questions