flutter-fix-layout-issues

flutter-fix-layout-issues

熱門

使用 Dart 和 Flutter MCP 工具修復 Flutter 版面配置錯誤(溢出、無限制約束)。適用於處理「RenderFlex overflowed」、「Vertical viewport was given unbounded height」或類似版面配置問題。

2525星標
152分支
更新於 2026/6/18
SKILL.md
唯讀
名稱
flutter-fix-layout-issues
描述

使用 Dart 和 Flutter MCP 工具修復 Flutter 版面配置錯誤(溢出、無限制約束)。適用於處理「RenderFlex overflowed」、「Vertical viewport was given unbounded height」或類似版面配置問題。

解決 Flutter 版面配置錯誤

目錄

約束違規診斷

Flutter 版面配置遵循嚴格規則:約束向下傳遞。尺寸向上回報。父層設定位置。 當此協商失敗時,就會發生版面配置錯誤,通常是因為無限制約束或未受約束的子元件。

根據以下錯誤特徵診斷版面配置失敗:

  • 「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 不是其必要祖先的直接後代時觸發(例如,Expanded 不在 Flex 內,Positioned 不在 Stack 內)。
  • 「RenderBox was not laid out」:這是一個連鎖副作用錯誤。請忽略此錯誤,並在堆疊追蹤中向上尋找主要的約束違規(通常是無限制高度/寬度錯誤)。

版面配置錯誤解決流程

複製並使用此檢查清單,系統性地解決版面配置約束違規。

任務進度

  • [ ] 以除錯模式執行應用程式,在控制台中擷取確切的版面配置例外。
  • [ ] 識別主要錯誤訊息(忽略連鎖的「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 熱重新載入。
  • [ ] 執行驗證器 -> 檢視錯誤 -> 修復:檢查 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.'),
    ),
  ],
)