Grid of categories with image and category name displayed below the image
Widget build(BuildContext context) {
return FutureBuilder(
future: categoriesService.getCategories(1),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.error != null) {
print('error ${snapshot.error}');
return Text(snapshot.error.toString());
}
// YOUR CUSTOM CODE GOES HERE
return Container(
// padding: const EdgeInsets.all(0.0),
child: GridView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
// childAspectRatio: 19 / 12,
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
),
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
Category category = snapshot.data[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
child: Image.network(
category.image,
fit: BoxFit.cover,
),
decoration: BoxDecoration(
border: Border.all(width: 1.0),
),
),
Text(category.name)
],
);
},
),
);
} else {
return new CircularProgressIndicator();
}
});
}
My child item has an image and category name. as seen in the image, currently child item is overflowing and we cant see the category name below the image, and unable to remove top space between image and border.
Original design is here
You could use the width and height of the device to calculate the aspect ratio dynamically. I have added a code sample based on yours showing how this could be done. Please note that you might need to adjust the provided aspect ratio slightly in order to fit your particular requirements.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class Category {
String name;
String image;
Category({this.name, this.image,});
}
class CategoriesService {
Future<List<Category>> getCategories(int value) async {
return <Category>[
Category(
name: 'FRESH CHICKEN',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'FRESH MUTTON',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'HALAL FROZEN FISH',
image: 'https://picsum.photos/400/300',
),
Category(
name: '2X STORE',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'FROZEN NONVEG DELIGHTS',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'FROZEN VEG DELIGHTS',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'DAL & PULSES',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'SPICES',
image: 'https://picsum.photos/400/300',
),
Category(
name: 'DRY FRUITS & NUTS',
image: 'https://picsum.photos/400/300',
),
];
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: FutureBuilder(
future: CategoriesService().getCategories(1),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.error != null) {
print('error ${snapshot.error}');
return Text(snapshot.error.toString());
}
// YOUR CUSTOM CODE GOES HERE
return Container(
// padding: const EdgeInsets.all(0.0),
child: GridView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.height / 1.4),
mainAxisSpacing: 10.0,
crossAxisSpacing: 10.0,
),
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
Category category = snapshot.data[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
child: Image.network(
category.image,
fit: BoxFit.cover,
),
decoration: BoxDecoration(
border: Border.all(width: 1.0),
),
),
Padding(
padding: const EdgeInsets.only(
top: 8.0,
),
child: Text(
category.name,
textAlign: TextAlign.center,
),
)
],
);
},
),
);
} else {
return new CircularProgressIndicator();
}
}),
),
);
}
}
You might find the below answers useful for additional information regarding the aspect ratio of the GridView
widget if you have not seen them already.
I find a way to set aspect ratio of biggest child to our Grid view dynamicly.
how it work ?
First please Look at this answer for . how we can find size of a widget during the build with overlayEntery
How to get a height of a Widget?
after that we set the right aspect ratio (Measured with overlayEntery ) to our Grid View in childAspectRatio.
I hope this help you .
I Make an Example ...
https://dartpad.dev/4821d71ec618d7d1f1f92f27458fde61
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class GridItemModel {
String longtext;
GlobalKey itemKey;
double width;
double height;
GridItemModel(this.longtext) {
itemKey = GlobalKey();
}
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget{
@override
State<StatefulWidget> createState() {
return _StateHomePage();
}
}
class _StateHomePage extends State<MyHomePage> {
// this first assign very important don't change it .
// if you change this part overlayEntry cant find biggest widget correctly .(cant see not scrolled items.)
// for test change to 1/1 and see what happening.
var myDynamicAspectRatio = 1000 / 1;
OverlayEntry sticky;
List<GridItemModel> myGridList = new List();
double maxHeight = 0;
double maxWidth = 0;
@override
void initState() {
if (sticky != null) {
sticky.remove();
}
sticky = OverlayEntry(
builder: (context) => stickyBuilder(context),
);
WidgetsBinding.instance.addPostFrameCallback((_) {
Overlay.of(context).insert(sticky);
setState(() {});
});
super.initState();
}
@override
void dispose() {
WidgetsBinding.instance.addPostFrameCallback((_) {
sticky.remove();
});
super.dispose();
}
@override
Widget build(BuildContext context) {
final title = 'Grid List';
return MaterialApp(
title: title,
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: GridView.count(
crossAxisCount: 2,
childAspectRatio: myDynamicAspectRatio,
children: List.generate(20, (index) {
myGridList.add(new GridItemModel(longTextMaker(index)));
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
key: myGridList[index].itemKey,
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
color: Colors.teal[index*100]
),
child: Text(
'Item $index' + myGridList[index].longtext,
style: Theme.of(context).textTheme.headline5,
),
),
],
);
}),
),
),
);
}
String longTextMaker(int count){
String result = "longText";
for(int i = 0 ; i < count; i++){
result += "longText" ;
}
return result;
}
shouldUpdateGridList(){
bool isChanged =false;
for(GridItemModel gi in myGridList) {
if(gi.width != null) {
if (gi.height > maxHeight) {
maxHeight = gi.height;
maxWidth = gi.width;
isChanged = true;
}
}
}
if(isChanged) {
myDynamicAspectRatio = maxWidth / maxHeight;
print("AspectRatio" + myDynamicAspectRatio.toString());
}
}
Widget stickyBuilder(BuildContext context) {
for(GridItemModel gi in myGridList) {
if(gi.width == null) {
final keyContext = gi.itemKey.currentContext;
if (keyContext != null) {
final box = keyContext.findRenderObject() as RenderBox;
print(box.size.height);
print(box.size.width);
gi.width = box.size.width;
gi.height = box.size.height;
}
}
}
shouldUpdateGridList();
return Container();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With