Unverified Commit c461ff9d authored by Shi-Hao Hong's avatar Shi-Hao Hong Committed by GitHub

Implement AlertDialog title/content overflow scroll (#43226)

* Wrap alert dialog title and content in single child scroll view

* Scrollable alert dialog title and content tests

* Remove unnecessary comment

* Fix mainAxisSize and crossAxisAlignment issue
parent 036c102c
...@@ -133,15 +133,6 @@ class Dialog extends StatelessWidget { ...@@ -133,15 +133,6 @@ class Dialog extends StatelessWidget {
/// of actions. The title is displayed above the content and the actions are /// of actions. The title is displayed above the content and the actions are
/// displayed below the content. /// displayed below the content.
/// ///
/// If the content is too large to fit on the screen vertically, the dialog will
/// display the title and the actions and let the content overflow, which is
/// rarely desired. Consider using a scrolling widget for [content], such as
/// [SingleChildScrollView], to avoid overflow. (However, be aware that since
/// [AlertDialog] tries to size itself using the intrinsic dimensions of its
/// children, widgets such as [ListView], [GridView], and [CustomScrollView],
/// which use lazy viewports, will not work. If this is a problem, consider
/// using [Dialog] directly.)
///
/// For dialogs that offer the user a choice between several options, consider /// For dialogs that offer the user a choice between several options, consider
/// using a [SimpleDialog]. /// using a [SimpleDialog].
/// ///
...@@ -161,13 +152,11 @@ class Dialog extends StatelessWidget { ...@@ -161,13 +152,11 @@ class Dialog extends StatelessWidget {
/// builder: (BuildContext context) { /// builder: (BuildContext context) {
/// return AlertDialog( /// return AlertDialog(
/// title: Text('Rewind and remember'), /// title: Text('Rewind and remember'),
/// content: SingleChildScrollView( /// content: Column(
/// child: ListBody( /// children: <Widget>[
/// children: <Widget>[ /// Text('You will never be satisfied.'),
/// Text('You will never be satisfied.'), /// Text('You\’re like me. I’m never satisfied.'),
/// Text('You\’re like me. I’m never satisfied.'), /// ],
/// ],
/// ),
/// ), /// ),
/// actions: <Widget>[ /// actions: <Widget>[
/// FlatButton( /// FlatButton(
...@@ -321,25 +310,34 @@ class AlertDialog extends StatelessWidget { ...@@ -321,25 +310,34 @@ class AlertDialog extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[ children: <Widget>[
if (title != null) if (title != null || content != 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( Flexible(
child: Padding( child: SingleChildScrollView(
padding: contentPadding, child: Column(
child: DefaultTextStyle( mainAxisSize: MainAxisSize.min,
style: contentTextStyle ?? dialogTheme.contentTextStyle ?? theme.textTheme.subhead, crossAxisAlignment: CrossAxisAlignment.stretch,
child: content, 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)
Padding(
padding: contentPadding,
child: DefaultTextStyle(
style: contentTextStyle ?? dialogTheme.contentTextStyle ?? theme.textTheme.subhead,
child: content,
),
),
],
), ),
), ),
), ),
......
...@@ -645,4 +645,81 @@ void main() { ...@@ -645,4 +645,81 @@ void main() {
await tester.pumpWidget(buildFrame(UniqueKey())); await tester.pumpWidget(buildFrame(UniqueKey()));
await tester.pump(); await tester.pump();
}); });
group('Scrollable title and content', () {
testWidgets('Title is scrollable', (WidgetTester tester) async {
final Key titleKey = UniqueKey();
final AlertDialog dialog = AlertDialog(
title: Container(
key: titleKey,
color: Colors.green,
height: 1000,
),
);
await tester.pumpWidget(_appWithAlertDialog(tester, dialog));
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
final RenderBox box = tester.renderObject(find.byKey(titleKey));
final Offset originalOffset = box.localToGlobal(Offset.zero);
await tester.drag(find.byKey(titleKey), const Offset(0.0, -200.0));
expect(box.localToGlobal(Offset.zero), equals(originalOffset.translate(0.0, -200.0)));
});
testWidgets('Content is scrollable', (WidgetTester tester) async {
final Key contentKey = UniqueKey();
final AlertDialog dialog = AlertDialog(
content: Container(
key: contentKey,
color: Colors.orange,
height: 1000,
),
);
await tester.pumpWidget(_appWithAlertDialog(tester, dialog));
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
final RenderBox box = tester.renderObject(find.byKey(contentKey));
final Offset originalOffset = box.localToGlobal(Offset.zero);
await tester.drag(find.byKey(contentKey), const Offset(0.0, -200.0));
expect(box.localToGlobal(Offset.zero), equals(originalOffset.translate(0.0, -200.0)));
});
testWidgets('Title and content are scrollable', (WidgetTester tester) async {
final Key titleKey = UniqueKey();
final Key contentKey = UniqueKey();
final AlertDialog dialog = AlertDialog(
title: Container(
key: titleKey,
color: Colors.green,
height: 400,
),
content: Container(
key: contentKey,
color: Colors.orange,
height: 400,
),
);
await tester.pumpWidget(_appWithAlertDialog(tester, dialog));
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
final RenderBox title = tester.renderObject(find.byKey(titleKey));
final RenderBox content = tester.renderObject(find.byKey(contentKey));
final Offset titleOriginalOffset = title.localToGlobal(Offset.zero);
final Offset contentOriginalOffset = content.localToGlobal(Offset.zero);
// Dragging the title widget should scroll both the title
// and the content widgets.
await tester.drag(find.byKey(titleKey), const Offset(0.0, -200.0));
expect(title.localToGlobal(Offset.zero), equals(titleOriginalOffset.translate(0.0, -200.0)));
expect(content.localToGlobal(Offset.zero), equals(contentOriginalOffset.translate(0.0, -200.0)));
// Dragging the content widget should scroll both the title
// and the content widgets.
await tester.drag(find.byKey(contentKey), const Offset(0.0, 200.0));
expect(title.localToGlobal(Offset.zero), equals(titleOriginalOffset));
expect(content.localToGlobal(Offset.zero), equals(contentOriginalOffset));
});
});
} }
...@@ -10,23 +10,23 @@ MaterialApp _appWithAlertDialog(WidgetTester tester, AlertDialog dialog, { Theme ...@@ -10,23 +10,23 @@ MaterialApp _appWithAlertDialog(WidgetTester tester, AlertDialog dialog, { Theme
return MaterialApp( return MaterialApp(
theme: theme, theme: theme,
home: Material( home: Material(
child: Builder( child: Builder(
builder: (BuildContext context) { builder: (BuildContext context) {
return Center( return Center(
child: RaisedButton( child: RaisedButton(
child: const Text('X'), child: const Text('X'),
onPressed: () { onPressed: () {
showDialog<void>( showDialog<void>(
context: context, context: context,
builder: (BuildContext context) { builder: (BuildContext context) {
return RepaintBoundary(key: _painterKey, child: dialog); return RepaintBoundary(key: _painterKey, child: dialog);
}, },
); );
}, },
), ),
); );
} },
), ),
), ),
); );
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment