flutter-fix-layout-issues

flutter-fix-layout-issues

熱門

使用 Dart 與 Flutter MCP 工具修復 Flutter 的排版錯誤(如內容溢位、無邊界約束問題)。當遇到「RenderFlex overflowed」、「Vertical viewport was given unbounded height」或類似的版面配置問題時使用。

2783星標
163分支
更新於 2026/8/5
SKILL.md
唯讀
名稱
flutter-fix-layout-issues
描述

使用 Dart 與 Flutter MCP 工具修復 Flutter 的排版錯誤(如內容溢位、無邊界約束問題)。當遇到「RenderFlex overflowed」、「Vertical viewport was given unbounded height」或類似的版面配置問題時使用。

解決 Flutter 版面配置錯誤

目錄

約束違規診斷

Flutter 的排版運作遵循一條嚴格的原則:約束向下傳遞,尺寸向上回傳,父元件決定位置(Constraints go down. Sizes go up. Parent sets position.)。當這套協商機制失敗時(通常是因為無邊界約束或未受約束的子元件),就會引發排版錯誤。

你可以透過以下錯誤特徵來診斷排版問題:

  • "Vertical viewport was given unbounded height":當可滾動元件(ListViewGridView)放置在未限制高度的垂直父元件(Column)內部時觸發。父元件提供了無限高度,而子元件嘗試無限延伸。
  • "An InputDecorator...cannot have an unbounded width":當 TextFieldTextFormField 放置在未限制寬度的水平父元件(Row)內部時觸發。文字輸入框嘗試在無限可用空間中計算自身的寬度。
  • "RenderFlex overflowed":當 RowColumn 的子元件要求的尺寸超過父元件所分配的約束時觸發。畫面上會以黃黑相間的警告條紋顯示。
  • "Incorrect use of ParentData widget":當 ParentDataWidget 不是其所要求的祖先元件的直接子代時觸發(例如在 Flex 外部使用 Expanded,或在 Stack 外部使用 Positioned)。
  • "RenderBox was not laid out":此為連帶引發的次要錯誤。請忽略此訊息,並往堆疊追蹤(stack trace)上方尋找主要的約束違規問題(通常是高度/寬度無邊界錯誤)。

排版錯誤解決流程

複製並使用以下檢查清單,系統化地解決排版約束違規問題。

任務進度

  • [ ] 在偵錯模式(debug mode)下執行應用程式,以在主控台(console)擷取確切的排版異常訊息。
  • [ ] 找出主要錯誤訊息(忽略連帶產生的 "RenderBox was not laid out" 錯誤)。
  • [ ] 根據具體錯誤類型採取對應的修復方式:
    • 若為 "Vertical viewport was given unbounded height":將可滾動的子元件(ListViewGridView)包裹在 Expanded 元件中以佔滿剩餘空間,或包裹在 SizedBox 中以提供明確的高度約束。
    • 若為 "An InputDecorator...cannot have an unbounded width":將 TextFieldTextFormField 包裹在 ExpandedFlexible 元件中。
    • 若為 "RenderFlex overflowed":限制溢位的子元件,將其包裹在 Expanded 元件中(強制符合可用空間),或包裹在 Flexible 元件中(允許縮小至小於分配空間)。
    • 若為 "Incorrect use of ParentData widget":將 ParentDataWidget 移動至其所要求之父元件的直接子代。確保 Expanded/FlexibleRow/Column/Flex 的直接子元件;確保 PositionedStack 的直接子元件。
  • [ ] 執行 Flutter 熱重載(hot reload)。
  • [ ] 執行驗證 -> 檢視錯誤 -> 修復:檢查 UI 以確認紅色/灰色錯誤畫面或黃黑相間的溢位條紋已消失。若出現新的排版錯誤,請重複執行此流程。

範例

修復無邊界高度問題(Column 中的 ListView)

輸入(錯誤狀態):

// 拋出 "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')),
      ],
    ),
  ],
)

輸出(已解決狀態):

// 將 ListView 包裹在 Expanded 中,將其高度限制在 Column 的剩餘空間內
Column(
  children: <Widget>[
    const Text('Header'),
    Expanded(
      child: ListView(
        children: const <Widget>[
          ListTile(title: Text('Item 1')),
          ListTile(title: Text('Item 2')),
        ],
      ),
    ),
  ],
)

修復無邊界寬度問題(Row 中的 TextField)

輸入(錯誤狀態):

// 拋出 "An InputDecorator...cannot have an unbounded width"
Row(
  children: [
    const Icon(Icons.search),
    TextField(), 
  ],
)

輸出(已解決狀態):

// 將 TextField 包裹在 Expanded 中,將其寬度限制在 Row 的剩餘空間內
Row(
  children: [
    const Icon(Icons.search),
    Expanded(
      child: TextField(),
    ),
  ],
)

修復 RenderFlex 溢位問題

輸入(錯誤狀態):

// 拋出 "A RenderFlex overflowed by X pixels on the right"
Row(
  children: [
    const Icon(Icons.info),
    const Text('This is a very long text string that will definitely overflow the available screen width and cause a RenderFlex error.'),
  ],
)

輸出(已解決狀態):

// 將 Text 元件包裹在 Expanded 中,強制其在可用約束內換行
Row(
  children: [
    const Icon(Icons.info),
    Expanded(
      child: const Text('This is a very long text string that will definitely overflow the available screen width and cause a RenderFlex error.'),
    ),
  ],
)