Search code examples
flutterdartgridviewsliver-grid

How to gridview item height make dynamic in flutter


I'm starting to learn the flutter language and I want to display the product list in GridView. But there is one problem that arises. When I run the app GridView items are displayed perfectly like the below image.

Without bottom overflow error

  • But when I close the app and open it again (note without the run) then I got a bottom overflow error. The image is below.

enter image description here

  • My Code is this
class HomePage extends StatefulWidget {
  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    loadData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(
          "Catalog App",
        ),
      ),
      body: (CatalogModel.products != null && CatalogModel.products!.isNotEmpty)
          ? Padding(
              padding: const EdgeInsets.all(1.0),
              child: GridView.builder(
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: 2,
                  childAspectRatio: MediaQuery.of(context).size.width /
                      (MediaQuery.of(context).size.height / 1.06),
                ),
                shrinkWrap: true,
                itemBuilder: (context, index) {
                  CatalogItem item = CatalogModel.products![index];
                  return Expanded(
                    child: InkWell(
                      onTap: () => Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (context) =>
                                  ProductDetails(item: item))),
                      child: Padding(
                        padding: const EdgeInsets.all(1.0),
                        child: Container(
                          decoration: const BoxDecoration(
                            color: Colors.white,
                          ),
                          child: Column(
                            children: [
                              SizedBox(
                                width: double.infinity,
                                height: 220,
                                child: Image.network(item.image,
                                    fit: BoxFit.cover),
                              ),
                              Padding(
                                  padding: const EdgeInsets.all(10.0),
                                  child: Column(children: [
                                    SizedBox(
                                      width: double.infinity,
                                      child: Text(item.name,
                                          textAlign: TextAlign.start,
                                          overflow: TextOverflow.ellipsis,
                                          style: GoogleFonts.cabin(
                                              fontSize: 16.0,
                                              textStyle: const TextStyle(
                                                fontWeight: FontWeight.bold,
                                              ))),
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.only(top: 5.0),
                                      child: SizedBox(
                                        width: double.infinity,
                                        child: Text(item.category,
                                            textAlign: TextAlign.start,
                                            style: GoogleFonts.cabin(
                                                textStyle: const TextStyle(
                                                    fontWeight: FontWeight.bold,
                                                    fontSize: 11.0,
                                                    color: Color(0xFF808080)))),
                                      ),
                                    ),
                                    PriceDetailsWidget(
                                        discount: item.discount,
                                        actual_price: item.actual_price,
                                        price: item.price),
                                    const AddToCartWidget(),
                                  ])),
                            ],
                          ),
                        ),
                      ),
                    ),
                  );
                },
                itemCount: CatalogModel.products?.length,
              ),
            )
          : const Center(
              child: CircularProgressIndicator(),
            ),
      drawer: MyDrawer(),
    );
  }

  void loadData() async {
    await Future.delayed(Duration(seconds: 5));
    final catalogJson =
        await rootBundle.loadString("assets/files/products.json");
    final decodedData = jsonDecode(catalogJson);
    final productData = decodedData["products"];
    CatalogModel.products = List.from(productData)
        .map<CatalogItem>((item) => CatalogItem.fromMap(item))
        .toList();
    setState(() {});
  }
}

PriceDetailsWidget.dart

class PriceDetailsWidget extends StatelessWidget {
  final String discount;
  final num price, actual_price;
  const PriceDetailsWidget({
    Key? key,
    required this.discount,
    required this.actual_price,
    required this.price,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(top: 8.0),
      child: SizedBox(
        width: double.infinity,
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text("\$${price}",
                textAlign: TextAlign.start,
                style: GoogleFonts.cabin(
                    textStyle: const TextStyle(
                        fontWeight: FontWeight.normal,
                        fontSize: 14.0,
                        decoration: TextDecoration.lineThrough,
                        decorationColor: Color(0xFF808080),
                        decorationThickness: 3.0,
                        color: Color(0xFF808080)))),
            Padding(
              padding: const EdgeInsets.only(left: 5.0),
              child: Text(
                "\$${actual_price}",
                style: const TextStyle(
                  color: Color(MyTheme.primaryColor),
                  fontWeight: FontWeight.bold,
                  fontSize: 14.0,
                ),
              ),
            ),
            Padding(
              padding: const EdgeInsets.only(left: 5.0),
              child: Text(
                discount,
                style: const TextStyle(
                  color: Colors.red,
                  fontWeight: FontWeight.normal,
                  fontSize: 14.0,
                ),
              ),
            )
          ],
        ),
      ),
    );
  }
}

AddToCartWidget.dart

class AddToCartWidget extends StatelessWidget {
  const AddToCartWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () {},
      style: ElevatedButton.styleFrom(elevation: 0.0, padding: EdgeInsets.zero),
      child: Row(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: const [
          Icon(
            // <-- Icon
            CupertinoIcons.cart_fill,
            size: 24.0,
          ),
          SizedBox(
            width: 5,
          ),
          Text('Add to cart'), // <-- Text
        ],
      ),
    );
  }
}

CatalogModel & CatalogItem

class CatalogModel {
  static List<CatalogItem>? products;
}

class CatalogItem {
  final String id;
  final String name;
  final String desc;
  final num price;
  final num actual_price;
  final String discount;
  final String color;
  final String image;
  final String category;
  CatalogItem(
      {required this.id,
      required this.name,
      required this.desc,
      required this.price,
      required this.actual_price,
      required this.discount,
      required this.color,
      required this.image,
      required this.category});

  factory CatalogItem.fromMap(Map<String, dynamic> map) => CatalogItem(
      id: map["id"],
      name: map["name"],
      desc: map["desc"],
      price: map["price"],
      actual_price: map["actual_price"],
      discount: map["discount"],
      color: map["color"],
      image: map["image"],
      category: map["category"]);

  toMap() => {
        "id": id,
        "name": name,
        "desc": desc,
        "price": price,
        "color": color,
        "image": image,
      };
}

products.json this file I'm storing in the assets folder

{
    "products": [
        {
            "id": "prod001",
            "name": "iPhone 13 Pro",
            "desc": "Your iPhone will arrive.",
            "price": 1299,
            "actual_price": 999,
            "discount": "20% off",
            "color": "#536858",
            "image": "https://d2xamzlzrdbdbn.cloudfront.net/products/66d6056e-e588-4b03-a44b-74685197003622111313.jpg",
            "category": "Mobile"
        },
        {
            "id": "prod002",
            "name": "iPhone SE (PRODUCT) RED",
            "desc": "iPhone SE (PRODUCT) RED",
            "price": 429,
            "actual_price": 399,
            "discount": "15% off",
            "color": "#A7090A",
            "image": "https://www.neolight.in/wp-content/uploads/2022/01/iPhone_XR_red.jpg",
            "category": "Mobile"
        }
    ]
}

Solution

  • TL, I write it here. Hot reload is working by injecting new, changed source code to the Dart VM which only works when debugging. So after you killed the app or closed the debug session, the VM is down. The only thing you left is the version you first installed when you start debug session. That's why when you reopen it after debug closed, the app is still showing the old error version.

    If you want to test it without debug session, you may either

    (1) build a release version

    (2) just close the debug session and start the debug session again, then the app installed should be the latest version

    Ref about hot reload in flutter