In Flutter's GridView.builder, how do SliverGridDelegateWithFixedCrossAxisCount and SliverGridDelegateWithMaxCrossAxisExtent decide each tile's size?
answer
- fixed column count versus max width
- column count rounds up
- childAspectRatio defaults to 1.0
- mainAxisExtent overrides the ratio
- tiles get tight constraints
basics
~20 sFixedCrossAxisCount divides the width into a set number of columns; MaxCrossAxisExtent picks the fewest columns no wider than a maximum. Height is width divided by childAspectRatio, default 1.0, unless mainAxisExtent is set, and each tile is forced to exactly that size.
solid answer
~40 s`GridView.builder` needs a `gridDelegate` and builds tiles lazily like `ListView.builder`. `SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3)` always makes three columns: tile width is the available width minus spacing, divided by three. `SliverGridDelegateWithMaxCrossAxisExtent(maxCrossAxisExtent: 150)` computes the column count by rounding **up** width / (max + spacing), so on a 500-wide grid it makes four columns of 125. For both, tile height is `width / childAspectRatio`, which defaults to **1.0** — square — unless `mainAxisExtent` sets it directly. `mainAxisSpacing` and `crossAxisSpacing` default to 0. Every tile gets **tight** constraints, so content taller than the computed height overflows; for tiles with an image and text, set `mainAxisExtent` rather than guessing a ratio. The max-extent delegate adapts the column count to tablets without breakpoints.
code
dart · 36 linesimport 'package:flutter/material.dart';
class PartsGrid extends StatelessWidget {
const PartsGrid({super.key, required this.names, required this.photos});
final List<String> names;
final List<ImageProvider> photos;
@override
Widget build(BuildContext context) {
return GridView.builder(
padding: const EdgeInsets.all(8),
itemCount: names.length,
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
mainAxisExtent: 240,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
),
itemBuilder: (BuildContext context, int index) {
return Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Expanded(child: Image(image: photos[index], fit: BoxFit.cover)),
Padding(
padding: const EdgeInsets.all(8),
child: Text(names[index], maxLines: 2, overflow: TextOverflow.ellipsis),
),
],
),
);
},
);
}
}go deeper
Know that GridView.builder needs a gridDelegate and that the two standard delegates fix the column count or the maximum tile width.
Compute tile sizes from width, spacing, childAspectRatio and mainAxisExtent, and explain the round-up column count.
Diagnose tile overflows from tight constraints, and pick the max-extent delegate for grids that must adapt across phones and tablets.
Standardise tile heights and grid delegates in the design system so catalogue screens stay consistent as text size and window width vary.
## GridView.builder `GridView.builder` is the lazy grid: `itemBuilder` runs only for tiles near the viewport, exactly as with `ListView.builder`. It adds one required parameter, `gridDelegate`, which decides the **tile geometry**. The convenience constructors `GridView.count` and `GridView.extent` take a `children` list instead, so they build every tile widget up front — fine for a dozen tiles, not for a 5,000-part catalogue. ## The two standard delegates | | `SliverGridDelegateWithFixedCrossAxisCount` | `SliverGridDelegateWithMaxCrossAxisExtent` | |---|---|---| | You choose | `crossAxisCount` | `maxCrossAxisExtent` | | Column count | fixed | `ceil(width / (maxCrossAxisExtent + crossAxisSpacing))`, at least 1 | | Tile width | (width minus spacing) / count | (width minus spacing) / count, never more than the max | | Adapts to screen width | no | yes | Shared parameters, with defaults: - `mainAxisSpacing: 0.0` — gap between rows; - `crossAxisSpacing: 0.0` — gap between columns; - `childAspectRatio: 1.0` — tile width divided by tile height; - `mainAxisExtent: null` — when set, the tile height in logical pixels, overriding the ratio. ## Worked examples 1. **Fixed count.** Width 800, `crossAxisCount: 4`, `childAspectRatio: 2.0`: tiles are 200 wide and 100 tall. 2. **Max extent.** Width 500, `maxCrossAxisExtent: 150`, no spacing: 500 / 150 is 3.33, rounded up to **4** columns of **125**. Rounding up is what keeps tiles at or below the maximum. 3. **Rotation.** The same max-extent grid at 900 wide gets 6 columns of 150 — no breakpoint code needed. ## Tight tiles and the overflow trap Each tile is laid out with **tight** constraints of exactly the computed width and height. Consequences: - A tile whose `Column` holds a part photo, a name and a price overflows if the computed height is too small — the familiar "bottom overflowed" stripe in debug mode. - Wrapping the tile in `AspectRatio` or `SizedBox` has no effect; the grid has already decided. - Guessing `childAspectRatio` to make a photo-plus-text tile fit breaks when the width or the text size changes. Setting `mainAxisExtent` fixes the height directly, and the content inside can use `Expanded` for the photo. ## Choosing - A fixed number of columns on every device, such as a two-column phone layout: **fixed count**. - Tiles that should stay about the same size while the column count adapts to phones, tablets and desktop windows: **max extent**. - Tiles of different sizes, or a masonry layout: neither — you need a custom `SliverGridDelegate` or a different layout. ## Other details - `GridView.builder` also takes `itemCount`; pass it so the grid has a known end. - The same keep-alive and repaint-boundary defaults as lists apply to tiles. - Horizontal grids swap the axes: the cross axis is vertical and rows play the part of columns.
- Why do GridView tiles overflow at the bottom after the text size is increased?Tile height comes from the delegate — width divided by `childAspectRatio`, or `mainAxisExtent` — and tiles get tight constraints. Larger text needs more height than the fixed tile allows. Give the tile a larger `mainAxisExtent`, let the image take the flexible space with `Expanded`, and cap text lines.
- How is GridView.count different from GridView.builder with a fixed-count delegate?`GridView.count` builds a fixed-count grid from a `children` list, so every tile widget is created up front. `GridView.builder` with `SliverGridDelegateWithFixedCrossAxisCount` lays tiles out the same way but builds them on demand, which suits long catalogues.
saying these in an interview costs you the question
- childAspectRatio is height divided by width.
- Grid tiles size themselves to their content by default.
- MaxCrossAxisExtent rounds the column count down.
- GridView.count builds its tiles lazily like GridView.builder.
- Wrapping a grid tile in AspectRatio changes the tile's shape.