Home > Blockchain >  Extract Listview.builder to use it with two lists in Flutter
Extract Listview.builder to use it with two lists in Flutter

Time:11-23

I'm a beginner in Flutter.

I designed this page:

enter image description here

Instead of repeating the entire Listview.builder. I would like to use two instances of custom Listview.builder with two lists, one list for fruits, and the other for vegetables.

As appeared in the above screen, I tried to display vegetables in the vegetables section through the following:

Listview.builder Widget:

import 'package:flutter/material.dart';
import 'package:grocery_store/models/products_list.dart';

import '../utilities/add_product.dart';
import '../utilities/constants.dart';

class ProductsListView extends StatelessWidget {
  final String? productImage;
  final String? productName;
  final String? productCategory;
  final String? productPrice;

  const ProductsListView({
    Key? key,
    this.productImage,
    this.productName,
    this.productCategory,
    this.productPrice,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      scrollDirection: Axis.horizontal,
      itemCount: fruitsList.length,
      itemBuilder: (BuildContext context, int index) {
        return ClipRect(
          child: Container(
            width: 140.0,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(15.0),
              color: Colors.white,
              boxShadow: const [
                BoxShadow(
                  blurRadius: 10,
                  color: Colors.black,
                ),
              ],
            ),
            margin: const EdgeInsets.all(10.0),
            child: Padding(
              padding: const EdgeInsets.fromLTRB(20, 10, 10, 10),
              child: Column(
                children: [
                  Image.asset(
                    fruitsList[index].fruitImage!,
                    height: 80.0,
                    width: 90.0,
                  ),
                  const SizedBox(
                    height: 15,
                  ),
                  Row(
                    children: [
                      Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            fruitsList[index].fruitName!,
                            style: const TextStyle(
                              fontSize: 15.0,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                          Text(
                            fruitsList[index].fruitCategory!,
                            textAlign: TextAlign.left,
                            style: const TextStyle(
                              height: 1.5,
                              color: kDarkGrey,
                              fontSize: 12.5,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                  Row(
                    children: [
                      Text(
                        fruitsList[index].fruitPrice!,
                        style: const TextStyle(
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      const Spacer(),
                      const AddProduct(),
                    ],
                  )
                ],
              ),
            ),
          ),
        );
      },
    );
  }
}

Fruits and vegetables lists:

import '../utilities/constants.dart';

class Fruits {
  final String? fruitImage;
  final String? fruitName;
  final String? fruitCategory;
  final String? fruitPrice;

  Fruits(
      {this.fruitImage, this.fruitName, this.fruitCategory, this.fruitPrice});
}

final Fruits bananas = Fruits(
  fruitImage: '${kFruitsImagesAsset}bananas.png',
  fruitName: 'Bananas',
  fruitCategory: 'Organic',
  fruitPrice: '\$4.99',
);

final Fruits apples = Fruits(
  fruitImage: '${kFruitsImagesAsset}apples.png',
  fruitName: 'Apples',
  fruitCategory: 'Organic',
  fruitPrice: '\$5.00',
);

final Fruits chikku = Fruits(
  fruitImage: '${kFruitsImagesAsset}chikku.png',
  fruitName: 'Chikku',
  fruitCategory: 'Organic',
  fruitPrice: '\$9.00',
);

final Fruits peaches = Fruits(
  fruitImage: '${kFruitsImagesAsset}peaches.png',
  fruitName: 'Peaches',
  fruitCategory: 'Organic',
  fruitPrice: '\$12.00',
);

List<Fruits> fruitsList = [bananas, apples, chikku, peaches];

class Vegetables {
  final String? vegetableImage;
  final String? vegetableName;
  final String? vegetableCategory;
  final String? vegetablePrice;

  Vegetables(
      {this.vegetableImage,
      this.vegetableName,
      this.vegetableCategory,
      this.vegetablePrice});
}

final Vegetables okra = Vegetables(
  vegetableImage: '${kVegetablesImagesAsset}okra.png',
  vegetableName: 'Okra',
  vegetableCategory: 'Organic',
  vegetablePrice: '\$6.99',
);

final Vegetables peas = Vegetables(
  vegetableImage: '${kVegetablesImagesAsset}peas.png',
  vegetableName: 'Peas',
  vegetableCategory: 'Organic',
  vegetablePrice: '\$10.50',
);

final Vegetables potatoes = Vegetables(
  vegetableImage: '${kVegetablesImagesAsset}potatoes.png',
  vegetableName: 'Potatoes',
  vegetableCategory: 'Organic',
  vegetablePrice: '\$5.99',
);

final Vegetables taro = Vegetables(
  vegetableImage: '${kVegetablesImagesAsset}taro.png',
  vegetableName: 'Taro',
  vegetableCategory: 'Organic',
  vegetablePrice: '\$5.50',
);

List<Vegetables> vegetablesList = [okra, peas, potatoes, taro];

Homepage where I want to display the two lists:

import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:grocery_store/models/product_cards_column.dart';
import 'package:grocery_store/utilities/constants.dart';
import 'package:grocery_store/utilities/grocery_text_field.dart';

import '../models/products_cards.dart';
import '../models/products_list.dart';

class GroceryPage extends StatelessWidget {
  const GroceryPage({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    var discountPortrait =
        MediaQuery.of(context).orientation == Orientation.portrait;

    return Scaffold(
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.all(15.0),
          child: SingleChildScrollView(
            child: Column(
              children: [
                Padding(
                  padding: const EdgeInsets.fromLTRB(10, 0, 1, 0),
                  child: Row(
                    children: [
                      const Text(
                        'Grocery',
                        style: kTitleTextStyle,
                      ),
                      const Spacer(),
                      ClipRRect(
                        borderRadius: BorderRadius.circular(16.0),
                        child: Image.asset(
                          'images/apple.jpg',
                          width: 46.0,
                          height: 46.0,
                          fit: BoxFit.cover,
                        ),
                      ),
                    ],
                  ),
                ),
                const SizedBox(height: 10.0),
                Row(children: [
                  GroceryTextField.groceryTextField(
                    groceryText: 'Search...',
                  ),
                  const SizedBox(width: 5.0),
                  Container(
                    height: 50.0,
                    width: 50.0,
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(18.0),
                      color: kLightGrey,
                    ),
                    child: Padding(
                      padding: const EdgeInsets.all(10.0),
                      child: SvgPicture.asset(
                        'images/funnel.svg',
                        semanticsLabel: 'Funnel',
                        color: kDarkGrey,
                      ),
                    ),
                  ),
                ]),
                const SizedBox(height: 10.0),
                Container(
                  height: 150,
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(30.0),
                    color: const Color(0xFFE9F9F2),
                  ),
                  width: double.infinity,
                  child: Stack(
                    children: [
                      Positioned(
                        bottom: -150,
                        right: discountPortrait ? -30 : 30,
                        height: 290,
                        width: 430,
                        child: Image.asset(
                          '${kProductsImagesAsset}lettuce.png',
                        ),
                      ),
                      Positioned(
                        top: discountPortrait ? 35 : 15,
                        left: discountPortrait ? 25 : 100,
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text(
                              'Get Up To',
                              style: kGreenTitleStyle.copyWith(
                                fontSize: discountPortrait ? 20 : 60,
                              ),
                            ),
                            Text(
                              ' off',
                              style: kGreenTitleStyle.copyWith(
                                fontSize: 40.0,
                              ),
                            ),
                          ],
                        ),
                      ),
                    ],
                  ),
                ),
                Column(
                  children: const [
                    ProductCardsRow(
                      groceryType: 'Fruits',
                    ),
                    SizedBox(
                      height: 215,
                      width: double.infinity,
                      child: ProductsListView(
                      ),
                    ),
                  ],
                ),
                Column(
                  children: const [
                    ProductCardsRow(
                      groceryType: 'Vegetables',
                    ),
                    SizedBox(
                      height: 215,
                      width: double.infinity,
                      child: ProductsListView(
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Hope someone can help

CodePudding user response:

Yeah it is pretty straightfroward, just click on the listview.builder method in your project and then click on FLutter Outline on the right hand side of the Android Studio IDE window, like this :

FLutter Outline

Once you have done that the ListView.Builder will be visible in this tree of widgets. What you need to do is to right click on the widget you want to extract and then click on extract method. you'll get a dialog asking for the name of the newly created widget :

Dialog Box for widget name

and a new widget will be created at the bottom of your file. Just change the parameters for both the listview.builders and it'll look something like this :

 Widget build(BuildContext context) {
   return CommonList(typeList: fruitslist); // use this to change the list
 }

And in the newly created widget you'd need to do the same:

class CommonList extends StatelessWidget {
  final List typeList; //add a list parameter 
  const CommonList({
    Key? key, required this.typeList, //request that list parameter
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      scrollDirection: Axis.horizontal,
      itemCount: typeList.length, // change the list type
      itemBuilder: (BuildContext context, int index) {
        return ClipRect(
          child: Container(
            width: 140.0,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(15.0),
              color: Colors.white,
              boxShadow: const [
                BoxShadow(
                  blurRadius: 10,
                  color: Colors.black,
                ),
              ],
            ),
            margin: const EdgeInsets.all(10.0),
            child: Padding(
              padding: const EdgeInsets.fromLTRB(20, 10, 10, 10),
              child: Column(
                children: [
                  Image.asset(
                    typeList[index].fruitImage!, //update list to use it everywhere
                    height: 80.0,
                    width: 90.0,
                  ),
                  const SizedBox(
                    height: 15,
                  ),
                  Row(
                    children: [
                      Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            typeList[index].fruitName!, //like here
                            style: const TextStyle(
                              fontSize: 15.0,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                          Text(
                            typeList[index].fruitCategory!, //here
                            textAlign: TextAlign.left,
                            style: const TextStyle(
                              height: 1.5,
                              color: kDarkGrey,
                              fontSize: 12.5,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                  Row(
                    children: [
                      Text(
                        typeList[index].fruitPrice!, //and here again
                        style: const TextStyle(
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      const Spacer(),
                      const AddProduct(),
                    ],
                  )
                ],
              ),
            ),
          ),
        );
      },
    );
  }

CodePudding user response:

You can set an other variable in constructor and call it list and pass your Vegetables and Fruits to it like this:

class ProductsListView extends StatelessWidget {
  final List list;

  const ProductsListView({
    Key? key,
    required this.list,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      scrollDirection: Axis.horizontal,
      itemCount: list.length,
      itemBuilder: (BuildContext context, int index) {
        
        return ClipRect(
          child: Container(
            width: 140.0,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(15.0),
              color: Colors.white,
              boxShadow: const [
                BoxShadow(
                  blurRadius: 10,
                  color: Colors.black,
                ),
              ],
            ),
            margin: const EdgeInsets.all(10.0),
            child: Padding(
              padding: const EdgeInsets.fromLTRB(20, 10, 10, 10),
              child: Column(
                children: [
                  Image.asset(
                    list is List<Fruits> ? (list[index] as Fruits).fruitImage! : (list[index] as Vegetables).vegetableImage!,
                    height: 80.0,
                    width: 90.0,
                  ),
                  const SizedBox(
                    height: 15,
                  ),
                  Row(
                    children: [
                      Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text(
                            list is List<Fruits> ? (list[index] as Fruits).fruitName! : (list[index] as Vegetables).vegetableName!,
                            style: const TextStyle(
                              fontSize: 15.0,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                          Text(
                            list is List<Fruits> ? (list[index] as Fruits).fruitCategory! : (list[index] as Vegetables).vegetableCategory!
                            
                            textAlign: TextAlign.left,
                            style: const TextStyle(
                              height: 1.5,
                              color: kDarkGrey,
                              fontSize: 12.5,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                  Row(
                    children: [
                      Text(
                        list is List<Fruits> ? (list[index] as Fruits).fruitPrice! : (list[index] as Vegetables).vegetablePrice!,
                        style: const TextStyle(
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      const Spacer(),
                      const AddProduct(),
                    ],
                  )
                ],
              ),
            ),
          ),
        );
      },
    );
  }
}
  • Related