在之前的 《iOS 26 鍵盤變化可能帶來大量底層改動》 我們就聊過,如下圖所示,是由於 iOS 26 系統鍵盤增加了「半透明」之後帶來的問題,Flutter 在鍵盤後面那一層在某些場景下沒有正確渲染內容,導致鍵盤半透明區域透出來的不是底下 BottomSheet 的真實內容,而是一整塊黑色區域。

因為過去 Flutter 的
Scaffold.resizeToAvoidBottomInset預設是true,所以鍵盤彈出時,Scaffold會把 body 縮到鍵盤上方,鍵盤區域一般由Scaffold.backgroundColor填充,這個模式在以前的 iOS 和 Android 上問題不大,因為鍵盤一直都是一個不透明矩形,就算後面顏色不對,使用者也看不到。
所以,過去 Flutter 的鍵盤避讓模式預設鍵盤是不透明、非圓角的,但 iOS 26 的 Liquid Glass 鍵盤變成半透明和圓角以後,問題就出現了,針對問題其實可以暫時選擇設定 UIDesignRequiresCompatibility = YES 來解決,或者改用 Dialog 來繞過場景,但是問題還是需要解決,所以官方認為有必要重構實作。
是不是太抽象了?我們可以透過更具體的例子來理解,原本 Flutter 裡的 Scaffold.resizeToAvoidBottomInset 預設是 true,所以當鍵盤彈出時,Scaffold 會根據 MediaQueryData.viewInsets.bottom 把 body 縮到鍵盤上方,正常來說應該是下面這樣的:
但是上面看起來沒問題,只是剛好場景沒遇到問題,如果是下面這種場景,在 iOS 26(圖 2)UI 就會變得很奇怪,因為正常互動上,他應該是圖 3 那種情況:

很明顯問題就出現在鍵盤下又多了一層的情況下,透明色和圓角就會讓 UI 變得割裂,而且就算不是透明色,圓角也會暴露出不友善的場景:

所以官方認為需要重構 Flutter 的鍵盤區域邏輯來適應這個問題,主要也是因為以前一直把鍵盤下方當成不可見區域,所以設計上一直沒有管理這一塊,所以這次官方定下重構的邏輯是:
layout 還是要避讓鍵盤,但 paint 不能停在鍵盤上方,背景繪製必須延伸到鍵盤背後。
說人話就是:內容不要真的排版到鍵盤下面,但背景色要畫到鍵盤下面。
同時官方也歸類出目前的鍵盤問題主要有三類:
類似 Scaffold.bottomSheet、showBottomSheet、ScaffoldState.showBottomSheet,它們本來就和 Scaffold 深度綁定,而且視覺上應該從 sheet 一直延續到鍵盤區域。
但 iOS 26 下如果 sheet 前景色和 Scaffold 背景色不一樣,鍵盤半透明後就會看到 Scaffold 背景色透出來,導致 sheet 和鍵盤區域斷開,也就是前面我們看到的問題。
所以這個問題應該 Flutter framework 自己處理,因為 Scaffold 本身就知道 persistent sheet 的存在,也能拿到 sheet 的背景色。
這類問題更麻煩,因為一般發生在業務自訂元件或第三方套件,類似:
Scaffold.body 的 descendantOverlayEntry 顯示,但不 push route比如這個灰色 barrier 只覆蓋到鍵盤頂部,鍵盤後面沒有繼續畫灰色,所以 iOS 26 半透明鍵盤會透出不一致的底色:

上圖問題主要來自 wolt_modal_sheet,它 push 了自己的 route,但 route 內部又有一個帶 persistent bottom sheet 的 Scaffold,而且 body 前景色和 Scaffold 背景色不同,所以還是會出現視覺斷層。
實際上這類問題主要是第三方套件自己實作的問題,比如:
viewInsets.bottom最後一個問題也是最容易遇到的,很多人寫 showModalBottomSheet 時,為了讓內容避開鍵盤,會手動加 .bottom:
showModalBottomSheet<void>(
context: context,
builder: (context) => Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.viewInsetsOf(context).bottom,
),
child: ColoredBox(
color: Colors.red,
child: ...
),
),
);
問題在於,如果你把背景色放在這個 Padding 裡面,顏色就只會覆蓋內容區域,不會覆蓋鍵盤區域:

這個結構的問題是Padding 在外,而顏色在內,內容被頂上去了,但顏色也跟著停在鍵盤上方。
所以正確寫法應該反過來,顏色在外,padding 在內,內容仍然避讓鍵盤,但背景色會延伸到鍵盤背後:
showModalBottomSheet<void>(
context: context,
builder: (context) => ColoredBox(
color: Colors.red,
child: Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.viewInsetsOf(context).bottom,
),
child: ...
),
),
);

這裡官方還收集了一批有問題的第三方生態套件,包括:
modal_bottom_sheetwolt_modal_sheetsmooth_sheetssliding_up_panelsnapping_sheetflutter_smart_dialogmotion_toastdelightful_toastanother_flushbarkeyboard_actionsshadcn_uifluent_uifor_ui很多套件都屬於第二種情況,因為過去大多預設軟鍵盤會繼續是不透明、非圓角的,所以大家基本上都沒有認真處理「鍵盤背後的背景應該由誰來畫」這個問題。
所以實際上的結果就是,官方要修 Flutter framework 這類第一種場景的情況,然後指導社群適配第二、第三種寫法。
針對 Flutter framework,官方初步是計畫在 Scaffold 層增加一個新的繪製 slot,用來在鍵盤區域畫 backdrop,這個 backdrop 的行為大概是:
resizeToAvoidBottomInset == true 時啟用IgnorePointer 包住,不改變點擊命中行為
也就是 Scaffold 仍然把 body 縮到鍵盤上方,但額外把 sheet 的背景色畫到鍵盤後面,這樣做的好處是相容性強,對 Android 和 iOS 26 之前的平台幾乎沒有可見影響,因為舊鍵盤本來就會擋住這塊區域。
當然,這種設計還是做不到原生 iOS 更理想的效果,如下圖是原生 iOS 的一個效果,列表是會經過模糊的半透明鍵盤:
因為 resizeToAvoidBottomInset 存在根本性缺陷,它實際上是為了調整 Flutter 主體大小來保持在鍵盤上方的行為而加入的,理想的鍵盤解決方案不是將 Scaffold body 的大小限制在鍵盤上方的區域,而是讓 Scaffold body 和所有 Scroll 視圖內部使用 viewInsets.bottom 來填充對應內容,這樣可捲動的內容在鍵盤下方也可以看到。
但是現在問題就出在:
viewInsets.bottom padding,裡面的 ListView / GridView / CustomScrollView 也加 padding,就會變成兩倍鍵盤高度。所以目前官方最終選擇了第三條路:
Scaffold 仍然負責鍵盤避讓,把鍵盤區域當成不可排版區域,但相關元件要把背景繪製延伸進去,保證視覺連續。
所以這個問題核心不只是 Flutter Framework 要修復,你用的套件和程式碼也需要跟著調整,而且這個實作看起來對漸層背景、圖片背景、blur / glass 效果的支援也不一定友善,所以只能算是一個折衷結果:
