flutter dart
npx skills add dhruvanbhalara/skills --skill flutter-fix-layout-issues

Contents

Constraint Model

Flutter layout operates on a strict negotiation rule:

Constraints go down. Sizes go up. Parent sets position.

  1. A parent widget passes constraints (min/max width and height) to its child.
  2. The child determines its own size within those constraints.
  3. The parent decides the child’s position.

Layout errors occur when this negotiation fails β€” typically when a parent provides unbounded constraints (infinite width or height) and the child attempts to expand infinitely.

Error Signature Catalog

Error Message Root Cause Quick Fix
Vertical viewport was given unbounded height Scrollable (ListView, GridView) inside unconstrained vertical parent (Column) Wrap in Expanded or SizedBox(height: ...)
An InputDecorator...cannot have an unbounded width TextField inside unconstrained horizontal parent (Row) Wrap in Expanded
A RenderFlex overflowed by X pixels Child exceeds parent’s allocated constraints Wrap in Expanded, Flexible, or use overflow: TextOverflow.ellipsis
Incorrect use of ParentData widget Expanded outside Flex, Positioned outside Stack Move widget to be direct child of correct parent
RenderBox was not laid out Cascading error β€” look upstream in stack trace Fix the primary constraint error above it

Rule: Always fix the first error in the stack trace. RenderBox was not laid out is almost always a cascading side effect.

Resolution Patterns

Decision Tree

Error detected
β”œβ”€β”€ Contains "unbounded height"?
β”‚   └── Wrap scrollable child in Expanded or SizedBox
β”œβ”€β”€ Contains "unbounded width"?
β”‚   └── Wrap TextField/InputDecorator in Expanded
β”œβ”€β”€ Contains "RenderFlex overflowed"?
β”‚   β”œβ”€β”€ Text overflow?
β”‚   β”‚   └── Add overflow: TextOverflow.ellipsis + Expanded wrapper
β”‚   └── Widget overflow?
β”‚       └── Wrap in Expanded or Flexible
β”œβ”€β”€ Contains "ParentData"?
β”‚   └── Ensure Expanded is direct child of Row/Column/Flex
β”‚       Ensure Positioned is direct child of Stack
└── Contains "RenderBox was not laid out"?
    └── IGNORE β€” fix the error above this one

Expanded vs Flexible vs SizedBox

Widget Behavior Use When
Expanded Forces child to fill ALL remaining space Child should stretch to fill
Flexible Allows child to be SMALLER than remaining space Child has natural size but shouldn’t overflow
SizedBox Provides absolute fixed constraints You know the exact dimension needed
ConstrainedBox Sets min/max constraints You need bounded flexibility

Workflow: Fixing Layout Issues

Task Progress

  • [ ] Step 1: Run app in debug mode β€” capture the exact exception in console.
  • [ ] Step 2: Identify the primary error message (ignore cascading RenderBox was not laid out).
  • [ ] Step 3: Match error against the Error Signature Catalog above.
  • [ ] Step 4: Apply the conditional fix:
    • If unbounded height β†’ wrap scrollable in Expanded or SizedBox
    • If unbounded width β†’ wrap input in Expanded
    • If RenderFlex overflowed β†’ wrap in Expanded or Flexible
    • If ParentData β†’ restructure widget tree
  • [ ] Step 5: Hot reload β†’ verify the error is resolved.
  • [ ] Step 6: If new layout errors appear β†’ repeat from Step 2.

Examples

Fixing Unbounded Height (ListView in Column)

Before (throws Vertical viewport was given unbounded height):

Column(
  children: <Widget>[
    const Text('Header'),
    ListView(
      children: const <Widget>[
        ListTile(title: Text('Item 1')),
        ListTile(title: Text('Item 2')),
      ],
    ),
  ],
)

After (resolved):

Column(
  children: <Widget>[
    const Text('Header'),
    Expanded(
      child: ListView(
        children: const <Widget>[
          ListTile(title: Text('Item 1')),
          ListTile(title: Text('Item 2')),
        ],
      ),
    ),
  ],
)

Fixing Unbounded Width (TextField in Row)

Before (throws An InputDecorator...cannot have an unbounded width):

Row(
  children: [
    const Icon(Icons.search),
    TextField(),
  ],
)

After (resolved):

Row(
  children: [
    const Icon(Icons.search),
    Expanded(
      child: TextField(),
    ),
  ],
)

Fixing RenderFlex Overflow (Text in Row)

Before (throws A RenderFlex overflowed by X pixels on the right):

Row(
  children: [
    const Icon(Icons.info),
    Text('This is a very long text that will overflow the screen width'),
  ],
)

After (resolved):

Row(
  children: [
    const Icon(Icons.info),
    Expanded(
      child: Text(
        'This is a very long text that will overflow the screen width',
        overflow: TextOverflow.ellipsis,
      ),
    ),
  ],
)

Fixing ParentData Misuse

Before (throws Incorrect use of ParentData widget):

// Expanded must be a DIRECT child of Row/Column/Flex
Container(
  child: Expanded(  // WRONG: Expanded not inside a Flex
    child: Text('Hello'),
  ),
)

After (resolved):

Row(
  children: [
    Expanded(  // OK: Direct child of Row (a Flex widget)
      child: Text('Hello'),
    ),
  ],
)