FX02: Unbounded List Height in Column
Resolve the classic vertical viewport unbounded height conflict between ListView and Column
Observed Symptom & Flutter Error Assertion
Vertical viewport was given unbounded height error during layout.
════╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
The following assertion was thrown during layout:
Vertical viewport was given unbounded height.
Viewports expand to fill their parent along the main axis. In this case, a vertical viewport was given
an unlimited amount of vertical space in which to expand. This usually happens when a scroll view is
nested inside another scroll view, or in a Column widget.
The relevant error-causing widget was:
ListView
lib/main.dart:24:15
════════════════════════════════════════════════════════════════════════════════════════════════════Declared Conditions
Placing a default scrollable ListView directly inside a Column without an explicit height constraint or Expanded/Flexible wrapper.
Column provides its children with unbounded vertical constraints (maxHeight = double.infinity). Meanwhile, a ListView viewport attempts to fill all available parent height. An infinite viewport inside an infinite parent cannot resolve geometry, triggering a layout assertion.
Wrap the ListView in an Expanded or Flexible widget so the Column allocates remaining bounded height, or give it a fixed SizedBox height constraint, or set shrinkWrap: true with physics: NeverScrollableScrollPhysics if nested inside another scrollable.
Fills remaining Column vertical space and lazily scrolls independently.
Corrected: Bounded via Expanded or SizedBox — expanded
Wrapping ListView in an Expanded widget tells the Column to give it all remaining bounded vertical space, enabling smooth bounded scrolling.
- ✓Enclose ListView inside an Expanded widget
- ✓ListView now receives bounded maxHeight equal to viewport height minus header
- ✓Clean independent scroll physics without layout crash
import 'package:flutter/material.dart';
void main() => runApp(const FixedExpandedListDemo());
class FixedExpandedListDemo extends StatelessWidget {
const FixedExpandedListDemo({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: const Text('Fixed: Expanded Column List'),
backgroundColor: const Color(0xFF0D9488),
),
body: Column(
children: [
const Padding(
padding: EdgeInsets.all(16),
child: Text('Full-Height List View', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
),
// STRATEGY 1: Expanded allocates all remaining Column height and enables lazy scrolling!
Expanded(
child: ListView.builder(
itemCount: 6,
itemBuilder: (context, index) => ListTile(
leading: const Icon(Icons.check_circle, color: Color(0xFF0D9488)),
title: Text('Scrollable Item ${index + 1}'),
subtitle: const Text('Lazily rendered with bounded constraints'),
),
),
),
],
),
),
);
}
}