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.
- 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.
- 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"
}
]
}
CodePudding user response:
use custom SliverGridDelegate for get what you want
import 'package:flutter/rendering.dart';
class SliverGridDelegateWithFixedCrossAxisCountAndFixedHeight
extends SliverGridDelegate {
const SliverGridDelegateWithFixedCrossAxisCountAndFixedHeight({
required this.crossAxisCount,
this.mainAxisSpacing = 0.0,
this.crossAxisSpacing = 0.0,
this.height = 56.0,
}) : assert(crossAxisCount != null && crossAxisCount > 0),
assert(mainAxisSpacing != null && mainAxisSpacing >= 0),
assert(crossAxisSpacing != null && crossAxisSpacing >= 0),
assert(height != null && height > 0);
final int crossAxisCount;
final double mainAxisSpacing;
final double crossAxisSpacing;
final double height;
bool _debugAssertIsValid() {
assert(crossAxisCount > 0);
assert(mainAxisSpacing >= 0.0);
assert(crossAxisSpacing >= 0.0);
assert(height > 0.0);
return true;
}
@override
SliverGridLayout getLayout(SliverConstraints constraints) {
assert(_debugAssertIsValid());
final double usableCrossAxisExtent =
constraints.crossAxisExtent - crossAxisSpacing * (crossAxisCount - 1);
final double childCrossAxisExtent = usableCrossAxisExtent / crossAxisCount;
final double childMainAxisExtent = height;
return SliverGridRegularTileLayout(
crossAxisCount: crossAxisCount,
mainAxisStride: childMainAxisExtent mainAxisSpacing,
crossAxisStride: childCrossAxisExtent crossAxisSpacing,
childMainAxisExtent: childMainAxisExtent,
childCrossAxisExtent: childCrossAxisExtent,
reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection),
);
}
@override
bool shouldRelayout(
SliverGridDelegateWithFixedCrossAxisCountAndFixedHeight oldDelegate) {
return oldDelegate.crossAxisCount != crossAxisCount ||
oldDelegate.mainAxisSpacing != mainAxisSpacing ||
oldDelegate.crossAxisSpacing != crossAxisSpacing ||
oldDelegate.height != height;
}
}
in this delegrate you can pass gridview item height
CodePudding user response:
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