桌面端上的默认 `PrimaryScrollController`
摘要
#PrimaryScrollController
API 已更新,不再自动附加到桌面平台上的垂直 ScrollView
。
上下文
#在此更改之前,如果 ScrollView
的滚动方向为 Axis.vertical
且尚未提供 ScrollController
,则 ScrollView.primary
会默认为 true。这使得常见的 UI 模式(例如 iOS 上的滚动到顶部功能)能够在 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
更改为可为空,并将回退决策转移到 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。 查看源代码 或 报告问题.