# Cause of Viewport Exception
`GridView` / `ListView` **grow** until *constraints* (limits) stop this expansion & then scroll to view items beyond that size.
But `Column` lays out its children *without* any constraints, **completely ignoring its own size and screen size**. There is infinite space inside of `Column`.
`Viewport was given unbounded height` exception occurs because `Grid/ListView` expands to infinity inside a `Column`.
`Flexible/Expanded` exist to give `Column` children constraints based `Column's` size. (These two widgets cannot be used anywhere else, except inside `Row` and `Column`.)
Inside a `Flexible/Expanded` widget in `Column`, `Grid/ListView` only uses remaining space not taken by other, non-flexible widgets, which get laid out first. (See bottom for layout phases info.)
# `shrinkWrap` is not a good solution
Using `shrinkWrap: true` on `ListView` inside a `Column` isn't really helpful as:
- `ListView` no longer scrolls
- `ListView` can still overflow
A `ListView` tall enough to show all of its items, will not scroll. Arguably defeats the purpose of using a `ScrollView` widget (parent class of `ListView`).
In `Column` layout phase 1 (see bottom for explanation of layout phases), `ListView` can be any height it wants (there are no constraints).
A `ListView` with `shrinkWrap:true` will grow in height to show all its items.
With enough items, a `shrinkWrapped` `ListView` will grow & grow (it never scrolls) to overflow whatever `Column` is inside, be it screen or other tighter constraint.
##### Shouldn't `shrinkWrap` just make `ListView` only as big as its items *OR* remaining space (up to screen height), and then scroll?
That would make intuitive sense, but inside a `Column` in phase 1 **layout is done in *unbounded space***.
So, remaining space is unlimited/infinite. A max height is never reached. `shrinkWrap:true` just keeps growing `Column` height as items are added until overflowing the screen (or other smaller constraint).
#### Example `shrinkWrap:true` Overflow
Here's an example of adding items to a shrinkwrapped `ListView` in a `Column` until its height is taller than the screen, creating an overflow warning area:
(just keep pressing the **+** sign Floating Action Button)
```
import 'package:flutter/material.dart';
class ColumnListViewPage extends StatefulWidget {
@override
_ColumnListViewPageState createState() => _ColumnListViewPageState();
}
class _ColumnListViewPageState extends State<ColumnListViewPage> {
int _count = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Column & ListView'),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
setState(() {
_count++;
});
},
),
body: SafeArea(
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.red)
),
/// // without center, Column will be as narrow as possible
alignment: Alignment.center,
/// Column is forced (constrained) to match screen dimension,
child: Column(
children: [
Text('Inner (Nested) Column'),
ListView.separated( // ← should be wrapped in Expanded
itemCount: _count,
separatorBuilder: (context, index) => const Divider(),
itemBuilder: (context, index) => Padding(
padding: const EdgeInsets.symmetric(vertical: 38.0),
child: Text('Row $index'),
),
shrinkWrap: true, // should be removed
)
],
),
),
),
);
}
}
```
##### For `GridView/ListView` in a `Column`, wrapping within `Expanded` or `Flexible` is likely the safest solution.
---
## Expanded / Flexible
`Expanded` and `Flexible` can only be used inside `Column` (and its siblings like `Row`, etc.).
They must be used as immediate children of `Column`. We can't "nest" `Expanded`/`Flexible` in `SizedBox` or other widgets. Only directly under `Column` as immediate children.
Inside `Column`, placing `ListView/GridView` in `Expanded` or `Flexible` ensures it will use only available space, rather than infinite space.
```
Column
→ Expanded
→ ListView
```
`ListView/GridView` inside `Expanded/Flexible` in a `Column` doesn't need `shrinkWrap` because it is constrained (given a max. height) by the `Expanded/Flexible` widget. So when that constrained/defined height is used up, `ListView/GridView` will stop growing & begin scrolling.
---
# Column Layout Phases
`Column` lays out children in 2 phases:
- 1st without constraints (unbounded space)
- 2nd with remaining space based on `Column's` parent
### Phase 1
Any `Column` child **not** inside `Flexible` or `Expanded` will be laid out in phase 1, in infinite, limitless space *completely ignoring screen size*.
Widgets that need a vertical boundary/constraint to limit their growth (e.g. `ListView`) will cause a `Vertical viewport was given unbounded height` exception in phase 1 as there *are no vertical bounds in unbounded space*.
Most widgets have intrinsic size. `Text` for example, is only as high as its content & font size/style. It doesn't try to grow to fill a space. Defined-height widgets play well in Phase 1 of `Column` layout.
### Phase 2
Any widget that grows to fill bounds, should be put in a `Flexible` or `Expanded` for Phase 2 layout.
Phase 2 calculates `Column's` remaining space from its parent constraints ***minus*** space used in Phase 1. This remaining space is provided to Phase 2 children as constraints.
`ListView` for example, will only grow to use remaining space & stop, avoiding viewport exceptions.
[More info on `Column` layout algorithm and how `Expanded` works within it][1].
[1]:
[To see links please register here]