Enable aligning a dropdown button's width with its menu's width (#14849)
This commit is contained in:
parent
01d8e0a143
commit
e1c38aa024
@ -64,16 +64,19 @@ class ButtonTheme extends InheritedWidget {
|
|||||||
double height: 36.0,
|
double height: 36.0,
|
||||||
EdgeInsetsGeometry padding,
|
EdgeInsetsGeometry padding,
|
||||||
ShapeBorder shape,
|
ShapeBorder shape,
|
||||||
|
bool alignedDropdown: false,
|
||||||
Widget child,
|
Widget child,
|
||||||
}) : assert(textTheme != null),
|
}) : assert(textTheme != null),
|
||||||
assert(minWidth != null && minWidth >= 0.0),
|
assert(minWidth != null && minWidth >= 0.0),
|
||||||
assert(height != null && height >= 0.0),
|
assert(height != null && height >= 0.0),
|
||||||
|
assert(alignedDropdown != null),
|
||||||
data = new ButtonThemeData(
|
data = new ButtonThemeData(
|
||||||
textTheme: textTheme,
|
textTheme: textTheme,
|
||||||
minWidth: minWidth,
|
minWidth: minWidth,
|
||||||
height: height,
|
height: height,
|
||||||
padding: padding,
|
padding: padding,
|
||||||
shape: shape,
|
shape: shape,
|
||||||
|
alignedDropdown: alignedDropdown
|
||||||
),
|
),
|
||||||
super(key: key, child: child);
|
super(key: key, child: child);
|
||||||
|
|
||||||
@ -98,16 +101,19 @@ class ButtonTheme extends InheritedWidget {
|
|||||||
double height: 36.0,
|
double height: 36.0,
|
||||||
EdgeInsetsGeometry padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
EdgeInsetsGeometry padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
ShapeBorder shape,
|
ShapeBorder shape,
|
||||||
|
bool alignedDropdown: false,
|
||||||
Widget child,
|
Widget child,
|
||||||
}) : assert(textTheme != null),
|
}) : assert(textTheme != null),
|
||||||
assert(minWidth != null && minWidth >= 0.0),
|
assert(minWidth != null && minWidth >= 0.0),
|
||||||
assert(height != null && height >= 0.0),
|
assert(height != null && height >= 0.0),
|
||||||
|
assert(alignedDropdown != null),
|
||||||
data = new ButtonThemeData(
|
data = new ButtonThemeData(
|
||||||
textTheme: textTheme,
|
textTheme: textTheme,
|
||||||
minWidth: minWidth,
|
minWidth: minWidth,
|
||||||
height: height,
|
height: height,
|
||||||
padding: padding,
|
padding: padding,
|
||||||
shape: shape,
|
shape: shape,
|
||||||
|
alignedDropdown: alignedDropdown,
|
||||||
),
|
),
|
||||||
super(key: key, child: child);
|
super(key: key, child: child);
|
||||||
|
|
||||||
@ -146,9 +152,11 @@ class ButtonThemeData extends Diagnosticable {
|
|||||||
this.height: 36.0,
|
this.height: 36.0,
|
||||||
EdgeInsetsGeometry padding,
|
EdgeInsetsGeometry padding,
|
||||||
ShapeBorder shape,
|
ShapeBorder shape,
|
||||||
|
this.alignedDropdown: false,
|
||||||
}) : assert(textTheme != null),
|
}) : assert(textTheme != null),
|
||||||
assert(minWidth != null && minWidth >= 0.0),
|
assert(minWidth != null && minWidth >= 0.0),
|
||||||
assert(height != null && height >= 0.0),
|
assert(height != null && height >= 0.0),
|
||||||
|
assert(alignedDropdown != null),
|
||||||
_padding = padding,
|
_padding = padding,
|
||||||
_shape = shape;
|
_shape = shape;
|
||||||
|
|
||||||
@ -229,6 +237,17 @@ class ButtonThemeData extends Diagnosticable {
|
|||||||
}
|
}
|
||||||
final ShapeBorder _shape;
|
final ShapeBorder _shape;
|
||||||
|
|
||||||
|
/// If true, then a [DropdownButton] menu's width will match the button's
|
||||||
|
/// width.
|
||||||
|
///
|
||||||
|
/// If false (the default), then the dropdown's menu will be wider than
|
||||||
|
/// its button. In either case the dropdown button will line up the leading
|
||||||
|
/// edge of the menu's value with the leading edge of the values
|
||||||
|
/// displayed by the menu items.
|
||||||
|
///
|
||||||
|
/// This property only affects [DropdownButton] and its menu.
|
||||||
|
final bool alignedDropdown;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(dynamic other) {
|
bool operator ==(dynamic other) {
|
||||||
if (other.runtimeType != runtimeType)
|
if (other.runtimeType != runtimeType)
|
||||||
@ -238,7 +257,8 @@ class ButtonThemeData extends Diagnosticable {
|
|||||||
&& minWidth == typedOther.minWidth
|
&& minWidth == typedOther.minWidth
|
||||||
&& height == typedOther.height
|
&& height == typedOther.height
|
||||||
&& padding == typedOther.padding
|
&& padding == typedOther.padding
|
||||||
&& shape == typedOther.shape;
|
&& shape == typedOther.shape
|
||||||
|
&& alignedDropdown == typedOther.alignedDropdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -249,6 +269,7 @@ class ButtonThemeData extends Diagnosticable {
|
|||||||
height,
|
height,
|
||||||
padding,
|
padding,
|
||||||
shape,
|
shape,
|
||||||
|
alignedDropdown,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,13 +277,15 @@ class ButtonThemeData extends Diagnosticable {
|
|||||||
void debugFillProperties(DiagnosticPropertiesBuilder description) {
|
void debugFillProperties(DiagnosticPropertiesBuilder description) {
|
||||||
super.debugFillProperties(description);
|
super.debugFillProperties(description);
|
||||||
final ButtonThemeData defaultTheme = const ButtonThemeData();
|
final ButtonThemeData defaultTheme = const ButtonThemeData();
|
||||||
description.add(new EnumProperty<ButtonTextTheme>('textTheme', textTheme,
|
description.add(new EnumProperty<ButtonTextTheme>('textTheme', textTheme, defaultValue: defaultTheme.textTheme));
|
||||||
defaultValue: defaultTheme.textTheme));
|
|
||||||
description.add(new DoubleProperty('minWidth', minWidth, defaultValue: defaultTheme.minWidth));
|
description.add(new DoubleProperty('minWidth', minWidth, defaultValue: defaultTheme.minWidth));
|
||||||
description.add(new DoubleProperty('height', height, defaultValue: defaultTheme.height));
|
description.add(new DoubleProperty('height', height, defaultValue: defaultTheme.height));
|
||||||
description.add(new DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding,
|
description.add(new DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: defaultTheme.padding));
|
||||||
defaultValue: defaultTheme.padding));
|
description.add(new DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: defaultTheme.shape));
|
||||||
description.add(
|
description.add(new FlagProperty('alignedDropdown',
|
||||||
new DiagnosticsProperty<ShapeBorder>('shape', shape, defaultValue: defaultTheme.shape));
|
value: alignedDropdown,
|
||||||
|
defaultValue: defaultTheme.alignedDropdown,
|
||||||
|
ifTrue: 'dropdown width matches button',
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import 'dart:math' as math;
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
import 'button_theme.dart';
|
||||||
import 'colors.dart';
|
import 'colors.dart';
|
||||||
import 'constants.dart';
|
import 'constants.dart';
|
||||||
import 'debug.dart';
|
import 'debug.dart';
|
||||||
@ -21,7 +22,11 @@ import 'theme.dart';
|
|||||||
const Duration _kDropdownMenuDuration = const Duration(milliseconds: 300);
|
const Duration _kDropdownMenuDuration = const Duration(milliseconds: 300);
|
||||||
const double _kMenuItemHeight = 48.0;
|
const double _kMenuItemHeight = 48.0;
|
||||||
const double _kDenseButtonHeight = 24.0;
|
const double _kDenseButtonHeight = 24.0;
|
||||||
const EdgeInsets _kMenuHorizontalPadding = const EdgeInsets.symmetric(horizontal: 16.0);
|
const EdgeInsets _kMenuItemPadding = const EdgeInsets.symmetric(horizontal: 16.0);
|
||||||
|
const EdgeInsetsGeometry _kAlignedButtonPadding = const EdgeInsetsDirectional.only(start: 16.0, end: 4.0);
|
||||||
|
const EdgeInsets _kUnalignedButtonPadding = EdgeInsets.zero;
|
||||||
|
const EdgeInsets _kAlignedMenuMargin = EdgeInsets.zero;
|
||||||
|
const EdgeInsetsGeometry _kUnalignedMenuMargin = const EdgeInsetsDirectional.only(start: 16.0, end: 24.0);
|
||||||
|
|
||||||
class _DropdownMenuPainter extends CustomPainter {
|
class _DropdownMenuPainter extends CustomPainter {
|
||||||
_DropdownMenuPainter({
|
_DropdownMenuPainter({
|
||||||
@ -91,10 +96,12 @@ class _DropdownScrollBehavior extends ScrollBehavior {
|
|||||||
class _DropdownMenu<T> extends StatefulWidget {
|
class _DropdownMenu<T> extends StatefulWidget {
|
||||||
const _DropdownMenu({
|
const _DropdownMenu({
|
||||||
Key key,
|
Key key,
|
||||||
|
this.padding,
|
||||||
this.route,
|
this.route,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final _DropdownRoute<T> route;
|
final _DropdownRoute<T> route;
|
||||||
|
final EdgeInsets padding;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_DropdownMenuState<T> createState() => new _DropdownMenuState<T>();
|
_DropdownMenuState<T> createState() => new _DropdownMenuState<T>();
|
||||||
@ -149,7 +156,7 @@ class _DropdownMenuState<T> extends State<_DropdownMenu<T>> {
|
|||||||
opacity: opacity,
|
opacity: opacity,
|
||||||
child: new InkWell(
|
child: new InkWell(
|
||||||
child: new Container(
|
child: new Container(
|
||||||
padding: _kMenuHorizontalPadding,
|
padding: widget.padding,
|
||||||
child: route.items[itemIndex],
|
child: route.items[itemIndex],
|
||||||
),
|
),
|
||||||
onTap: () => Navigator.pop(
|
onTap: () => Navigator.pop(
|
||||||
@ -212,7 +219,7 @@ class _DropdownMenuRouteLayout<T> extends SingleChildLayoutDelegate {
|
|||||||
final double maxHeight = math.max(0.0, constraints.maxHeight - 2 * _kMenuItemHeight);
|
final double maxHeight = math.max(0.0, constraints.maxHeight - 2 * _kMenuItemHeight);
|
||||||
// The width of a menu should be at most the view width. This ensures that
|
// The width of a menu should be at most the view width. This ensures that
|
||||||
// the menu does not extend past the left and right edges of the screen.
|
// the menu does not extend past the left and right edges of the screen.
|
||||||
final double width = math.min(constraints.maxWidth, buttonRect.width + 8.0);
|
final double width = math.min(constraints.maxWidth, buttonRect.width);
|
||||||
return new BoxConstraints(
|
return new BoxConstraints(
|
||||||
minWidth: width,
|
minWidth: width,
|
||||||
maxWidth: width,
|
maxWidth: width,
|
||||||
@ -238,7 +245,7 @@ class _DropdownMenuRouteLayout<T> extends SingleChildLayoutDelegate {
|
|||||||
double left;
|
double left;
|
||||||
switch (textDirection) {
|
switch (textDirection) {
|
||||||
case TextDirection.rtl:
|
case TextDirection.rtl:
|
||||||
left = buttonRect.right.clamp(0.0, size.width - childSize.width) - childSize.width;
|
left = buttonRect.right.clamp(0.0, size.width) - childSize.width;
|
||||||
break;
|
break;
|
||||||
case TextDirection.ltr:
|
case TextDirection.ltr:
|
||||||
left = buttonRect.left.clamp(0.0, size.width - childSize.width);
|
left = buttonRect.left.clamp(0.0, size.width - childSize.width);
|
||||||
@ -279,6 +286,7 @@ class _DropdownRouteResult<T> {
|
|||||||
class _DropdownRoute<T> extends PopupRoute<_DropdownRouteResult<T>> {
|
class _DropdownRoute<T> extends PopupRoute<_DropdownRouteResult<T>> {
|
||||||
_DropdownRoute({
|
_DropdownRoute({
|
||||||
this.items,
|
this.items,
|
||||||
|
this.padding,
|
||||||
this.buttonRect,
|
this.buttonRect,
|
||||||
this.selectedIndex,
|
this.selectedIndex,
|
||||||
this.elevation: 8,
|
this.elevation: 8,
|
||||||
@ -288,6 +296,7 @@ class _DropdownRoute<T> extends PopupRoute<_DropdownRouteResult<T>> {
|
|||||||
}) : assert(style != null);
|
}) : assert(style != null);
|
||||||
|
|
||||||
final List<DropdownMenuItem<T>> items;
|
final List<DropdownMenuItem<T>> items;
|
||||||
|
final EdgeInsetsGeometry padding;
|
||||||
final Rect buttonRect;
|
final Rect buttonRect;
|
||||||
final int selectedIndex;
|
final int selectedIndex;
|
||||||
final int elevation;
|
final int elevation;
|
||||||
@ -336,7 +345,12 @@ class _DropdownRoute<T> extends PopupRoute<_DropdownRouteResult<T>> {
|
|||||||
scrollController = new ScrollController(initialScrollOffset: scrollOffset);
|
scrollController = new ScrollController(initialScrollOffset: scrollOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget menu = new _DropdownMenu<T>(route: this);
|
final TextDirection textDirection = Directionality.of(context);
|
||||||
|
Widget menu = new _DropdownMenu<T>(
|
||||||
|
route: this,
|
||||||
|
padding: padding.resolve(textDirection),
|
||||||
|
);
|
||||||
|
|
||||||
if (theme != null)
|
if (theme != null)
|
||||||
menu = new Theme(data: theme, child: menu);
|
menu = new Theme(data: theme, child: menu);
|
||||||
|
|
||||||
@ -353,7 +367,7 @@ class _DropdownRoute<T> extends PopupRoute<_DropdownRouteResult<T>> {
|
|||||||
buttonRect: buttonRect,
|
buttonRect: buttonRect,
|
||||||
menuTop: menuTop,
|
menuTop: menuTop,
|
||||||
menuHeight: menuHeight,
|
menuHeight: menuHeight,
|
||||||
textDirection: Directionality.of(context),
|
textDirection: textDirection,
|
||||||
),
|
),
|
||||||
child: menu,
|
child: menu,
|
||||||
);
|
);
|
||||||
@ -566,11 +580,16 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
|
|||||||
void _handleTap() {
|
void _handleTap() {
|
||||||
final RenderBox itemBox = context.findRenderObject();
|
final RenderBox itemBox = context.findRenderObject();
|
||||||
final Rect itemRect = itemBox.localToGlobal(Offset.zero) & itemBox.size;
|
final Rect itemRect = itemBox.localToGlobal(Offset.zero) & itemBox.size;
|
||||||
|
final TextDirection textDirection = Directionality.of(context);
|
||||||
|
final EdgeInsetsGeometry menuMargin = ButtonTheme.of(context).alignedDropdown
|
||||||
|
?_kAlignedMenuMargin
|
||||||
|
: _kUnalignedMenuMargin;
|
||||||
|
|
||||||
assert(_dropdownRoute == null);
|
assert(_dropdownRoute == null);
|
||||||
_dropdownRoute = new _DropdownRoute<T>(
|
_dropdownRoute = new _DropdownRoute<T>(
|
||||||
items: widget.items,
|
items: widget.items,
|
||||||
buttonRect: _kMenuHorizontalPadding.inflateRect(itemRect),
|
buttonRect: menuMargin.resolve(textDirection).inflateRect(itemRect),
|
||||||
|
padding: _kMenuItemPadding.resolve(textDirection),
|
||||||
selectedIndex: _selectedIndex ?? 0,
|
selectedIndex: _selectedIndex ?? 0,
|
||||||
elevation: widget.elevation,
|
elevation: widget.elevation,
|
||||||
theme: Theme.of(context, shadowThemeOnly: true),
|
theme: Theme.of(context, shadowThemeOnly: true),
|
||||||
@ -613,9 +632,14 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final EdgeInsetsGeometry padding = ButtonTheme.of(context).alignedDropdown
|
||||||
|
? _kAlignedButtonPadding
|
||||||
|
: _kUnalignedButtonPadding;
|
||||||
|
|
||||||
Widget result = new DefaultTextStyle(
|
Widget result = new DefaultTextStyle(
|
||||||
style: _textStyle,
|
style: _textStyle,
|
||||||
child: new SizedBox(
|
child: new Container(
|
||||||
|
padding: padding.resolve(Directionality.of(context)),
|
||||||
height: widget.isDense ? _denseButtonHeight : null,
|
height: widget.isDense ? _denseButtonHeight : null,
|
||||||
child: new Row(
|
child: new Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
@ -491,7 +491,7 @@ class ThemeData extends Diagnosticable {
|
|||||||
Color unselectedWidgetColor,
|
Color unselectedWidgetColor,
|
||||||
Color disabledColor,
|
Color disabledColor,
|
||||||
Color buttonColor,
|
Color buttonColor,
|
||||||
Color buttonTheme,
|
ButtonThemeData buttonTheme,
|
||||||
Color secondaryHeaderColor,
|
Color secondaryHeaderColor,
|
||||||
Color textSelectionColor,
|
Color textSelectionColor,
|
||||||
Color textSelectionHandleColor,
|
Color textSelectionHandleColor,
|
||||||
|
@ -14,6 +14,7 @@ void main() {
|
|||||||
expect(theme.shape, const RoundedRectangleBorder(
|
expect(theme.shape, const RoundedRectangleBorder(
|
||||||
borderRadius: const BorderRadius.all(const Radius.circular(2.0)),
|
borderRadius: const BorderRadius.all(const Radius.circular(2.0)),
|
||||||
));
|
));
|
||||||
|
expect(theme.alignedDropdown, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ButtonThemeData default overrides', () {
|
test('ButtonThemeData default overrides', () {
|
||||||
@ -23,11 +24,13 @@ void main() {
|
|||||||
height: 200.0,
|
height: 200.0,
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
shape: const RoundedRectangleBorder(),
|
shape: const RoundedRectangleBorder(),
|
||||||
|
alignedDropdown: true,
|
||||||
);
|
);
|
||||||
expect(theme.textTheme, ButtonTextTheme.primary);
|
expect(theme.textTheme, ButtonTextTheme.primary);
|
||||||
expect(theme.constraints, const BoxConstraints(minWidth: 100.0, minHeight: 200.0));
|
expect(theme.constraints, const BoxConstraints(minWidth: 100.0, minHeight: 200.0));
|
||||||
expect(theme.padding, EdgeInsets.zero);
|
expect(theme.padding, EdgeInsets.zero);
|
||||||
expect(theme.shape, const RoundedRectangleBorder());
|
expect(theme.shape, const RoundedRectangleBorder());
|
||||||
|
expect(theme.alignedDropdown, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('ButtonTheme defaults', (WidgetTester tester) async {
|
testWidgets('ButtonTheme defaults', (WidgetTester tester) async {
|
||||||
@ -173,4 +176,109 @@ void main() {
|
|||||||
expect(tester.widget<Material>(find.byType(Material)).color, const Color(0xFF00FF00));
|
expect(tester.widget<Material>(find.byType(Material)).color, const Color(0xFF00FF00));
|
||||||
expect(tester.getSize(find.byType(Material)), const Size(100.0, 200.0));
|
expect(tester.getSize(find.byType(Material)), const Size(100.0, 200.0));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('ButtonTheme alignedDropdown', (WidgetTester tester) async {
|
||||||
|
final Key dropdownKey = new UniqueKey();
|
||||||
|
|
||||||
|
Widget buildFrame({ bool alignedDropdown, TextDirection textDirection }) {
|
||||||
|
return new MaterialApp(
|
||||||
|
builder: (BuildContext context, Widget child) {
|
||||||
|
return new Directionality(
|
||||||
|
textDirection: textDirection,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
home: new ButtonTheme(
|
||||||
|
alignedDropdown: alignedDropdown,
|
||||||
|
child: new Material(
|
||||||
|
child: new Builder(
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return new Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: new DropdownButtonHideUnderline(
|
||||||
|
child: new Container(
|
||||||
|
width: 200.0,
|
||||||
|
child: new DropdownButton<String>(
|
||||||
|
key: dropdownKey,
|
||||||
|
onChanged: (String value) { },
|
||||||
|
value: 'foo',
|
||||||
|
items: const <DropdownMenuItem<String>>[
|
||||||
|
const DropdownMenuItem<String>(
|
||||||
|
value: 'foo',
|
||||||
|
child: const Text('foo'),
|
||||||
|
),
|
||||||
|
const DropdownMenuItem<String>(
|
||||||
|
value: 'bar',
|
||||||
|
child: const Text('bar'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Finder button = find.byKey(dropdownKey);
|
||||||
|
final Finder menu = find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_DropdownMenu<String>');
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildFrame(
|
||||||
|
alignedDropdown: false,
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.tap(button);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// 240 = 200.0 (button width) + _kUnalignedMenuMargin (20.0 left and right)
|
||||||
|
expect(tester.getSize(button).width, 200.0);
|
||||||
|
expect(tester.getSize(menu).width, 240.0);
|
||||||
|
|
||||||
|
// Dismiss the menu.
|
||||||
|
await tester.tapAt(Offset.zero);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(menu, findsNothing);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildFrame(
|
||||||
|
alignedDropdown: true,
|
||||||
|
textDirection: TextDirection.ltr,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.tap(button);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// Aligneddropdown: true means the button and menu widths match
|
||||||
|
expect(tester.getSize(button).width, 200.0);
|
||||||
|
expect(tester.getSize(menu).width, 200.0);
|
||||||
|
|
||||||
|
// There are two 'foo' widgets: the selected menu item's label and the drop
|
||||||
|
// down button's label. The should both appear at the same location.
|
||||||
|
final Finder fooText = find.text('foo');
|
||||||
|
expect(fooText, findsNWidgets(2));
|
||||||
|
expect(tester.getRect(fooText.at(0)), tester.getRect(fooText.at(1)));
|
||||||
|
|
||||||
|
// Dismiss the menu.
|
||||||
|
await tester.tapAt(Offset.zero);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
expect(menu, findsNothing);
|
||||||
|
|
||||||
|
// Same test as above execpt RTL
|
||||||
|
await tester.pumpWidget(
|
||||||
|
buildFrame(
|
||||||
|
alignedDropdown: true,
|
||||||
|
textDirection: TextDirection.rtl,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await tester.tap(button);
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
expect(fooText, findsNWidgets(2));
|
||||||
|
expect(tester.getRect(fooText.at(0)), tester.getRect(fooText.at(1)));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user