桌機上的預設 `PrimaryScrollController`
摘要
#PrimaryScrollController
API 已更新,不再自動附加到桌機平台上的垂直 ScrollView
。
上下文
#在此變更之前,如果 ScrollView
具有 Axis.vertical
滾動方向且尚未提供 ScrollController
,則 ScrollView.primary
將預設為 true。這使得 iOS 上的捲動到頂部功能等常見 UI 模式可以直接用於 Flutter 應用程式。然而,在桌機上,此預設值通常會導致以下斷言錯誤:
ScrollController attached to multiple ScrollViews.
雖然行動應用程式一次顯示一個 ScrollView
很常見,但桌機 UI 模式更可能並排顯示多個 ScrollView
。PrimaryScrollController
之前的實作與此模式衝突,導致出現通常沒有幫助的錯誤訊息。為了補救此問題,PrimaryScrollController
已更新,新增了其他參數,並改善了多個依賴它的 Widget 的錯誤訊息。
變更說明
#ScrollView
之前的實作導致在所有平台上,所有沒有 ScrollController
的垂直 ScrollView
的 primary
預設為 true。這種預設行為並非總是清晰,特別是因為它與 PrimaryScrollController
本身是分開的。
// Previously, this ListView would always result in primary being true,
// and attached to the PrimaryScrollController on all platforms.
Scaffold(
body: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Text('Item $index');
}
),
);
實作變更 ScrollView.primary
為可為 null,並將後備決策移至 PrimaryScrollController
。當 primary
為 null 且未提供 ScrollController
時,ScrollView
將查找 PrimaryScrollController
並改為呼叫 shouldInherit
以確定給定的 ScrollView
是否應使用 PrimaryScrollController
。
PrimaryScrollController
類別的新成員 automaticallyInheritForPlatforms
和 scrollDirection
,會在 shouldInherit
中評估,讓使用者清楚且可控制 PrimaryScrollController
的行為。
預設情況下,行動平台的向後相容性會維持。PrimaryScrollController.shouldInherit
對於垂直 ScrollView
回傳 true。在桌機上,此預設值回傳 false。
// Only on mobile platforms will this attach to the PrimaryScrollController by
// default.
Scaffold(
body: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Text('Item $index');
}
),
);
若要變更預設值,使用者可以將 ScrollView.primary
設定為 true 或 false,以明確管理個別 ScrollView
的 PrimaryScrollController
。對於多個 ScrollView
的行為,現在可以透過設定特定平台以及繼承偏好的滾動方向來配置 PrimaryScrollController
。
使用 PrimaryScrollController
的 Widget,例如 NestedScrollView
、Scrollbar
和 DropdownMenuButton
,現有功能不會發生任何變更。諸如 iOS 捲動到頂部等功能也將繼續正常運作,而無需任何遷移。
桌機上的 ScrollAction
和 ScrollIntent
是此變更唯一影響的類別,需要遷移。預設情況下,如果目前的 Focus
包含在 Scrollable
中,則 PrimaryScrollController
會用於執行後備鍵盤滾動 Shortcuts
。由於在桌機平台上並排顯示多個 ScrollView
很常見,因此 Flutter 無法決定「此視圖中哪個 ScrollView
應該是主要的並接收鍵盤滾動動作?」
如果在此變更之前存在多個 ScrollView
,則會拋出相同的斷言 (ScrollController attached to multiple ScrollViews.
)。現在,在桌機平台上,使用者需要指定 primary: true
,以指定哪個 ScrollView
是接收未處理鍵盤 Shortcuts
的後備。
遷移指南
#遷移前的程式碼
// These side-by-side ListViews would throw errors from Scrollbars and
// ScrollActions previously due to the PrimaryScrollController.
Scaffold(
body: LayoutBuilder(
builder: (context, constraints) {
return Row(
children: [
SizedBox(
height: constraints.maxHeight,
width: constraints.maxWidth / 2,
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Text('List 1 - Item $index');
}
),
),
SizedBox(
height: constraints.maxHeight,
width: constraints.maxWidth / 2,
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Text('List 2 - Item $index');
}
),
),
]
);
},
),
);
遷移後的程式碼
// These side-by-side ListViews will no longer throw errors, but for
// default ScrollActions, one will need to be designated as primary.
Scaffold(
body: LayoutBuilder(
builder: (context, constraints) {
return Row(
children: [
SizedBox(
height: constraints.maxHeight,
width: constraints.maxWidth / 2,
child: ListView.builder(
// This ScrollView will use the PrimaryScrollController
primary: true,
itemBuilder: (BuildContext context, int index) {
return Text('List 1 - Item $index');
}
),
),
SizedBox(
height: constraints.maxHeight,
width: constraints.maxWidth / 2,
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Text('List 2 - Item $index');
}
),
),
]
);
},
),
);
時程表
#已於版本中發佈:3.3.0-0.0.pre
在穩定版本中:3.3
參考資料
#API 文件
設計文件
相關問題
相關 PR
除非另有說明,否則本網站上的文件反映 Flutter 的最新穩定版本。頁面上次更新於 2024-05-14。 檢視來源 或 回報問題。