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

Reland Alert dialog overflow spacing (#50675)

* Add ButtonBar.overflowButtonSpacing

* Add AlertDialog overflow button spacing functionality
parent 450fc25c
......@@ -65,9 +65,11 @@ class ButtonBar extends StatelessWidget {
this.buttonAlignedDropdown,
this.layoutBehavior,
this.overflowDirection,
this.overflowButtonSpacing,
this.children = const <Widget>[],
}) : assert(buttonMinWidth == null || buttonMinWidth >= 0.0),
assert(buttonHeight == null || buttonHeight >= 0.0),
assert(overflowButtonSpacing == null || overflowButtonSpacing >= 0.0),
super(key: key);
/// How the children should be placed along the horizontal axis.
......@@ -143,6 +145,22 @@ class ButtonBar extends StatelessWidget {
/// default to [VerticalDirection.down].
final VerticalDirection overflowDirection;
/// The spacing between buttons when the button bar overflows.
///
/// If the [children] do not fit into a single row, they are
/// arranged into a column. This parameter provides additional
/// vertical space in between buttons when it does overflow.
///
/// Note that the button spacing may appear to be more than
/// the value provided. This is because most buttons adhere to the
/// [MaterialTapTargetSize] of 48px. So, even though a button
/// might visually be 36px in height, it might still take up to
/// 48px vertically.
///
/// If null then no spacing will be added in between buttons in
/// an overflow state.
final double overflowButtonSpacing;
/// The buttons to arrange horizontally.
///
/// Typically [RaisedButton] or [FlatButton] widgets.
......@@ -176,6 +194,7 @@ class ButtonBar extends StatelessWidget {
child: child,
);
}).toList(),
overflowButtonSpacing: overflowButtonSpacing,
),
);
switch (buttonTheme.layoutBehavior) {
......@@ -226,6 +245,7 @@ class _ButtonBarRow extends Flex {
TextDirection textDirection,
VerticalDirection overflowDirection = VerticalDirection.down,
TextBaseline textBaseline,
this.overflowButtonSpacing,
}) : super(
children: children,
direction: direction,
......@@ -237,6 +257,8 @@ class _ButtonBarRow extends Flex {
textBaseline: textBaseline,
);
final double overflowButtonSpacing;
@override
_RenderButtonBarRow createRenderObject(BuildContext context) {
return _RenderButtonBarRow(
......@@ -247,6 +269,7 @@ class _ButtonBarRow extends Flex {
textDirection: getEffectiveTextDirection(context),
verticalDirection: verticalDirection,
textBaseline: textBaseline,
overflowButtonSpacing: overflowButtonSpacing,
);
}
......@@ -259,7 +282,8 @@ class _ButtonBarRow extends Flex {
..crossAxisAlignment = crossAxisAlignment
..textDirection = getEffectiveTextDirection(context)
..verticalDirection = verticalDirection
..textBaseline = textBaseline;
..textBaseline = textBaseline
..overflowButtonSpacing = overflowButtonSpacing;
}
}
......@@ -289,7 +313,9 @@ class _RenderButtonBarRow extends RenderFlex {
@required TextDirection textDirection,
VerticalDirection verticalDirection = VerticalDirection.down,
TextBaseline textBaseline,
this.overflowButtonSpacing,
}) : assert(textDirection != null),
assert(overflowButtonSpacing == null || overflowButtonSpacing >= 0),
super(
children: children,
direction: direction,
......@@ -302,6 +328,7 @@ class _RenderButtonBarRow extends RenderFlex {
);
bool _hasCheckedLayoutWidth = false;
double overflowButtonSpacing;
@override
BoxConstraints get constraints {
......@@ -391,6 +418,9 @@ class _RenderButtonBarRow extends RenderFlex {
child = childParentData.previousSibling;
break;
}
if (overflowButtonSpacing != null && child != null)
currentHeight += overflowButtonSpacing;
}
size = constraints.constrain(Size(constraints.maxWidth, currentHeight));
}
......
......@@ -20,6 +20,7 @@ import 'ink_well.dart';
import 'material.dart';
import 'material_localizations.dart';
import 'theme.dart';
import 'theme_data.dart';
// Examples can assume:
// enum Department { treasury, state }
......@@ -223,6 +224,7 @@ class AlertDialog extends StatelessWidget {
this.actions,
this.actionsPadding = EdgeInsets.zero,
this.actionsOverflowDirection,
this.actionsOverflowButtonSpacing,
this.buttonPadding,
this.backgroundColor,
this.elevation,
......@@ -342,6 +344,22 @@ class AlertDialog extends StatelessWidget {
/// * [ButtonBar], which [actions] configures to lay itself out.
final VerticalDirection actionsOverflowDirection;
/// The spacing between [actions] when the button bar overflows.
///
/// If the widgets in [actions] do not fit into a single row, they are
/// arranged into a column. This parameter provides additional
/// vertical space in between buttons when it does overflow.
///
/// Note that the button spacing may appear to be more than
/// the value provided. This is because most buttons adhere to the
/// [MaterialTapTargetSize] of 48px. So, even though a button
/// might visually be 36px in height, it might still take up to
/// 48px vertically.
///
/// If null then no spacing will be added in between buttons in
/// an overflow state.
final double actionsOverflowButtonSpacing;
/// The padding that surrounds each button in [actions].
///
/// This is different from [actionsPadding], which defines the padding
......@@ -445,6 +463,7 @@ class AlertDialog extends StatelessWidget {
child: ButtonBar(
buttonPadding: buttonPadding,
overflowDirection: actionsOverflowDirection,
overflowButtonSpacing: actionsOverflowButtonSpacing,
children: actions,
),
);
......
......@@ -570,7 +570,60 @@ void main() {
final Rect containerOneRect = tester.getRect(find.byKey(keyOne));
final Rect containerTwoRect = tester.getRect(find.byKey(keyTwo));
// Second [Container] should appear above first container.
expect(containerTwoRect.bottom, containerOneRect.top);
expect(containerTwoRect.bottom, lessThanOrEqualTo(containerOneRect.top));
},
);
testWidgets(
'ButtonBar has no spacing by default when overflowing',
(WidgetTester tester) async {
final Key keyOne = UniqueKey();
final Key keyTwo = UniqueKey();
await tester.pumpWidget(
MaterialApp(
home: ButtonBar(
alignment: MainAxisAlignment.center,
// Set padding to zero to align buttons with edge of button bar.
buttonPadding: EdgeInsets.zero,
children: <Widget>[
Container(key: keyOne, height: 50.0, width: 500.0),
Container(key: keyTwo, height: 50.0, width: 500.0),
],
),
),
);
final Rect containerOneRect = tester.getRect(find.byKey(keyOne));
final Rect containerTwoRect = tester.getRect(find.byKey(keyTwo));
expect(containerOneRect.bottom, containerTwoRect.top);
},
);
testWidgets(
"ButtonBar's children respects overflowButtonSpacing when overflowing",
(WidgetTester tester) async {
final Key keyOne = UniqueKey();
final Key keyTwo = UniqueKey();
await tester.pumpWidget(
MaterialApp(
home: ButtonBar(
alignment: MainAxisAlignment.center,
// Set padding to zero to align buttons with edge of button bar.
buttonPadding: EdgeInsets.zero,
// Set the overflow button spacing to ensure add some space between
// buttons in an overflow case.
overflowButtonSpacing: 10.0,
children: <Widget>[
Container(key: keyOne, height: 50.0, width: 500.0),
Container(key: keyTwo, height: 50.0, width: 500.0),
],
),
),
);
final Rect containerOneRect = tester.getRect(find.byKey(keyOne));
final Rect containerTwoRect = tester.getRect(find.byKey(keyTwo));
expect(containerOneRect.bottom, containerTwoRect.top - 10.0);
},
);
});
......
......@@ -557,7 +557,7 @@ void main() {
); // right
});
testWidgets('Dialogs can set the vertical direction of actions', (WidgetTester tester) async {
testWidgets('Dialogs can set the vertical direction of overflowing actions', (WidgetTester tester) async {
final GlobalKey key1 = GlobalKey();
final GlobalKey key2 = GlobalKey();
......@@ -589,7 +589,74 @@ void main() {
final Rect buttonOneRect = tester.getRect(find.byKey(key1));
final Rect buttonTwoRect = tester.getRect(find.byKey(key2));
// Second [RaisedButton] should appear above the first.
expect(buttonTwoRect.bottom, buttonOneRect.top);
expect(buttonTwoRect.bottom, lessThanOrEqualTo(buttonOneRect.top));
});
testWidgets('Dialogs have no spacing by default for overflowing actions', (WidgetTester tester) async {
final GlobalKey key1 = GlobalKey();
final GlobalKey key2 = GlobalKey();
final AlertDialog dialog = AlertDialog(
title: const Text('title'),
content: const Text('content'),
actions: <Widget>[
RaisedButton(
key: key1,
onPressed: () {},
child: const Text('Looooooooooooooong button 1'),
),
RaisedButton(
key: key2,
onPressed: () {},
child: const Text('Looooooooooooooong button 2'),
),
],
);
await tester.pumpWidget(
_buildAppWithDialog(dialog),
);
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
final Rect buttonOneRect = tester.getRect(find.byKey(key1));
final Rect buttonTwoRect = tester.getRect(find.byKey(key2));
expect(buttonOneRect.bottom, buttonTwoRect.top);
});
testWidgets('Dialogs can set the button spacing of overflowing actions', (WidgetTester tester) async {
final GlobalKey key1 = GlobalKey();
final GlobalKey key2 = GlobalKey();
final AlertDialog dialog = AlertDialog(
title: const Text('title'),
content: const Text('content'),
actions: <Widget>[
RaisedButton(
key: key1,
onPressed: () {},
child: const Text('Looooooooooooooong button 1'),
),
RaisedButton(
key: key2,
onPressed: () {},
child: const Text('Looooooooooooooong button 2'),
),
],
actionsOverflowButtonSpacing: 10.0,
);
await tester.pumpWidget(
_buildAppWithDialog(dialog),
);
await tester.tap(find.text('X'));
await tester.pumpAndSettle();
final Rect buttonOneRect = tester.getRect(find.byKey(key1));
final Rect buttonTwoRect = tester.getRect(find.byKey(key2));
expect(buttonOneRect.bottom, buttonTwoRect.top - 10.0);
});
testWidgets('Dialogs removes MediaQuery padding and view insets', (WidgetTester tester) async {
......
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