avoid_shrink_wrap_in_lists
v0.4.0 Warning Fix Widget Best Practices
Flags shrinkWrap: true on a ListView.
Shrink-wrapping makes the list measure every child up front, off-screen ones included, so it can size itself. That is exactly the lazy layout a ListView exists to provide. On a long list it is visible jank; on a very long one it is an ANR.
This rule is in the opinionated preset, so it is on with preset: opinionated and preset: pedantic. No configuration.
See also: ScrollView.shrinkWrap
final orders = ListView( shrinkWrap: true, children: const [Text('Order 1'), Text('Order 2')],);ListView.builder is reported the same way:
final lazyOrders = ListView.builder( shrinkWrap: true, itemCount: 500, itemBuilder: (context, index) => Text('Order $index'),);Drop the argument. shrinkWrap defaults to false, which is what the quick fix does:
final orders = ListView( children: const [Text('Order 1'), Text('Order 2')],);When the list is inside another scrollable
Section titled “When the list is inside another scrollable”This is why shrinkWrap: true usually got added — a ListView inside a Column inside a SingleChildScrollView has no bounded height, and removing the argument alone surfaces an unbounded-height error instead.
The fix there is to stop nesting scrollables and make the whole page one CustomScrollView. The quick fix cannot make that call for you:
// Don't — two scrollables, the inner one shrink-wrapped to fitSingleChildScrollView( child: Column( children: [ const Text('Recent orders'), ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: 500, itemBuilder: (context, index) => Text('Order $index'), ), ], ),);
// Do — one scrollable, laid out lazilyCustomScrollView( slivers: [ const SliverToBoxAdapter(child: Text('Recent orders')), SliverList( delegate: SliverChildBuilderDelegate( (context, index) => Text('Order $index'), childCount: 500, ), ), ],);A fixed-height box is the cheap alternative
Section titled “A fixed-height box is the cheap alternative”When the list really is short and the page really is a Column, giving it a height is simpler than restructuring:
SizedBox( height: 240, child: ListView.builder( itemCount: 4, itemBuilder: (context, index) => Text('Order $index'), ),);Known limitations
Section titled “Known limitations”Only ListView is reported. GridView, SingleChildScrollView and other ScrollView subclasses accept the same argument with the same cost, but are left alone.
shrinkWrap: someBoolean is not reported — only a literal true is.
Turning this rule off
Section titled “Turning this rule off”rules: avoid_shrink_wrap_in_lists: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”always_pass_global_key— Don’t create a GlobalKey inside build.avoid_conditional_hooks— Never call hooks inside conditionals, loops, or ternaries.avoid_deep_widget_nesting— Keep a widget tree within a nesting budget.avoid_flexible_outside_flex— Only use Flexible and Expanded as direct children of Row, Column, or Flex.