Ashwin S Ashok
Ashwin S Ashok

Reputation: 3663

Proper method for setting childAspectRatio in flutter

What is the proper way of calculating childAspectRatio of SliverGridDelegateWithFixedCrossAxisCount in flutter. How to manage the the correct height of each view that is compatible with all devices and should work in landscape and portrait

GridView.builder(
    physics: BouncingScrollPhysics(),
    padding: const EdgeInsets.all(4.0),
    itemCount: snapshot.data.results.length,
    gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(
      crossAxisCount: itemCount,
      childAspectRatio: 0.501,
      mainAxisSpacing: 4.0,
      crossAxisSpacing: 4.0,
    ),
    itemBuilder: (BuildContext context, int index) {
      return GridTile(
          child: _buildGridItem(context, snapshot.data.results[index]));
    });

Upvotes: 10

Views: 9992

Answers (1)

Egor
Egor

Reputation: 10344

DISCLAIMER: This is theoretical explanation of how GridView works. Proposed solution is not designed for heavy content. Use GridView theory that I describe here to build layout that you desire.

Let me start with crossAxisCount, which is supposed to be interpreted as a number of columns in a table.

e.g. crossAxisCount: 3,

|  cell-1  ||  cell-2  ||  cell-3  |
------------------------------------ // new row after every 3 cells
|  cell-4  ||  cell-5  ||  cell-6  |

What flutter does with crossAxisCount: N, is tries to fit exactly N number of cells in a row. Hence, width of one individual cell will equal grid width divided by N.

e.g. crossAxisCount: 3, -> cellWidth = parentWidth / 3 (pseudocode)


Now, what happens next is calculation of cell's height using childAspectRatio that your initial question is about.

e.g. cellWidth = parentWidth / crossAxisCount & cellHeight = cellWidth / childAspectRatio.

This way, you should interpret childAspectRatio as a ratio of every individual cell's width to its height (and vice versa).


I assume you noticed that GridView is rather limited when it comes to unusually structured layout.

In case you truly think that GridView is not enough for what you are trying to build - I'd recommend using other widgets that support multiple children layout. For instance, I use Wrap widget to display very fluid content, in which every element has its own dynamic width & height.

I am not aware of what type of layout you need, but in case of a very dynamic / fluid yet light concept you can try using Wrap:

@override
Widget build(BuildContext context) {
  final mediaQuery = MediaQuery.of(context);
  return SingleChildScrollView(
    child: Wrap(
      children: List.generate(totalItemsToDisplay, (index) {
        final cellWidth = mediaQuery.size.width / 3; // Every cell's `width` will be set to 1/3 of the screen width.
        return SizedBox(
          width: cellWidth,
          // You can either use some static number for `height`, or set ratio to cellWidth.
          // Setting `height` to `null` should work too, which would make height of a cell auto-resizable according to its content.
          height: 123,
          child: ...,
        );
      })
    )
  );
}

However, I would not recommend using this to display large sets of data.

If your goal is to display a set of posts / articles / pictures etc., something that initially implies structured heavy content - I would recommend going with GridView by standardising cells height through childAspectRatio.

Upvotes: 5

Related Questions