可滚动的 AlertDialog (不再弃用)
概述
Summary
AlertDialog
现在会在绘制溢出时自动变为可滚动状态。
An AlertDialog
now scrolls automatically when it overflows.
上下文
Context
在此更改之前,当 AlertDialog
widget 中的内容过高时,会显示绘制溢出,使内容被剪裁。这会导致以下问题:
Before this change,
when an AlertDialog
widget’s contents were too tall,
the display overflowed, causing the contents to be clipped.
This resulted in the following issues:
-
无法查看被剪裁的内容。
There was no way to view the portion of the content that was clipped.
-
大多数
AlertDialog
的内容下方都有按钮,用于提示用户执行操作。如果内容溢出,遮盖了按钮,用户可能不知道它们的存在。Most alert dialogs have buttons beneath the content to prompt users for actions. If the content overflowed, obscuring the buttons, users might be unaware of their existence.
更改描述
Description of change
在改动前,可以使用下面的方法在 Column
widget 中连续地列出标题和内容 widget。
The previous approach listed the title and content
widgets consecutively in a Column
widget.
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
if (title != null)
Padding(
padding: titlePadding ?? EdgeInsets.fromLTRB(24.0, 24.0, 24.0, content == null ? 20.0 : 0.0),
child: DefaultTextStyle(
style: titleTextStyle ?? dialogTheme.titleTextStyle ?? theme.textTheme.title,
child: Semantics(
child: title,
namesRoute: true,
container: true,
),
),
),
if (content != null)
Flexible(
child: Padding(
padding: contentPadding,
child: DefaultTextStyle(
style: contentTextStyle ?? dialogTheme.contentTextStyle ?? theme.textTheme.subhead,
child: content,
),
),
),
// ...
],
);
在改动后,它们被包裹在按钮栏上方的 SingleChildScrollView
中,作为同一个可滚动的模块的一部分,按钮栏将显示在对话框底部。
The new approach wraps both widgets in a
SingleChildScrollView
above the button bar,
making both widgets part of the same scrollable
and exposing the button bar at the bottom of the dialog.
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
if (title != null || content != null)
SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
if (title != null)
titleWidget,
if (content != null)
contentWidget,
],
),
),
// ...
],
),
迁移指南
Migration guide
此更改可能会导致以下问题:
You might see the following issues as a result of this change:
- Semantics tests might fail because of the addition of a
SingleChildScrollView
. - Manual testing of the
Talkback
andVoiceOver
features show that they still exhibit the same (correct) behavior as before.
由于添加了 SingleChildScrollView
,语义测试可能会失败。
对 Talkback
和 VoiceOver
功能的手动测试表明,它们仍然表现出与以前相同的(正确的)行为。
- Golden tests might fail.
- This change might have caused diffs in (previously passing)
golden tests since the
SingleChildScrollView
now nests both the title and content widgets. Some Flutter projects have taken to creating semantics tests by taking goldens of semantics nodes used in Flutter’s debug build.
Golden Test 可能会失败。
由于 SingleChildScrollView
现在嵌套了标题和内容 widget,因此可能导致 Golden Test 出现不同的结果。一些 Flutter 项目已经开始通过获取 Flutter debug 构建过程中使用的语义节点 goldens 来创建语义测试。
滚动容器上附加的所有语义 golden 变动都是符合预期的,它们不会造成其他后果。
Any semantics golden updates that reflect the scrolling
container addition are expected and these diffs should be safe to accept.
语义树示例:
Sample resulting Semantics tree:
flutter: ├─SemanticsNode#30 <-- SingleChildScrollView
flutter: │ flags: hasImplicitScrolling
flutter: │ scrollExtentMin: 0.0
flutter: │ scrollPosition: 0.0
flutter: │ scrollExtentMax: 0.0
flutter: │
flutter: ├─SemanticsNode#31 <-- title
flutter: │ flags: namesRoute
flutter: │ label: "Hello"
flutter: │
flutter: └─SemanticsNode#32 <-- contents
flutter: label: "Huge content"
- Layout changes might result because of the scroll view.
- If the dialog was already overflowing, this change corrects the problem. This layout change is expected.
滚动视图可能导致布局更改。
该变更会修复对话框发生绘制溢出的问题。这种布局上的变化是意料之中的。
当代码中有 SingleChildScrollView
嵌套在
AlertDialog.content
时,那么对话框应正常展示。但如果不是有意为之,则应将其移除,否则可能导致代码更为不可读。
A nested SingleChildScrollView
in AlertDialog.content
should work properly if left in the code,
but should be removed if unintended, since
it might cause confusion.
迁移前的代码:
Code before migration:
AlertDialog(
title: Text(
'Very, very large title that is also scrollable',
textScaleFactor: 5,
),
content: SingleChildScrollView( // won't be scrollable
child: Text('Scrollable content', textScaleFactor: 5),
),
actions: <Widget>[
TextButton(child: Text('Button 1'), onPressed: () {}),
TextButton(child: Text('Button 2'), onPressed: () {}),
],
)
迁移后的代码:
Code after migration:
AlertDialog(
title: Text('Very, very large title', textScaleFactor: 5),
content: Text('Very, very large content', textScaleFactor: 5),
actions: <Widget>[
TextButton(child: Text('Button 1'), onPressed: () {}),
TextButton(child: Text('Button 2'), onPressed: () {}),
],
)
时间线
Timeline
发布于版本:1.16.3
发布于稳定版本:1.17
Landed in version: 1.16.3
In stable release: 1.17
参考文献
References
设计文档
Design doc:
API 文档:
API documentation:
相关 issue:
Relevant issue:
相关 PRs:
Relevant PRs: