Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to calculate childAspectRatio for GridView.builder in flutter

Tags:

flutter

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.

enter image description here

Original design is here

enter image description here

like image 448
maaz Avatar asked Jun 30 '20 21:06

maaz


2 Answers

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();
          }
        }),
      ),
    );
  }
}

iPad Pro iPhone X Galaxy S5

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.

  • How to set Custom height for Widget in GridView in Flutter?
  • How to set grid view column height?
  • flutter how to give height to the childrens of GridView.Builder
like image 113
tnc1997 Avatar answered Oct 25 '22 00:10

tnc1997


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();
  }
}

like image 10
mohandesR Avatar answered Oct 24 '22 23:10

mohandesR