Add disabledHint
to DropdownButton (#18770)
If `items` or `onChanged` is null the button will be disabled, the down arrow will be grayed out, and the new `disabledHint` will be shown (if provided).
This commit is contained in:
parent
707eaf5edf
commit
6b79d37797
@ -493,6 +493,8 @@ class DropdownButton<T> extends StatefulWidget {
|
|||||||
/// Creates a dropdown button.
|
/// Creates a dropdown button.
|
||||||
///
|
///
|
||||||
/// The [items] must have distinct values and if [value] isn't null it must be among them.
|
/// The [items] must have distinct values and if [value] isn't null it must be among them.
|
||||||
|
/// If [items] or [onChanged] is null, the button will be disabled, the down arrow will be grayed out, and
|
||||||
|
/// the [disabledHint] will be shown (if provided).
|
||||||
///
|
///
|
||||||
/// The [elevation] and [iconSize] arguments must not be null (they both have
|
/// The [elevation] and [iconSize] arguments must not be null (they both have
|
||||||
/// defaults, so do not need to be specified).
|
/// defaults, so do not need to be specified).
|
||||||
@ -501,14 +503,14 @@ class DropdownButton<T> extends StatefulWidget {
|
|||||||
@required this.items,
|
@required this.items,
|
||||||
this.value,
|
this.value,
|
||||||
this.hint,
|
this.hint,
|
||||||
|
this.disabledHint,
|
||||||
@required this.onChanged,
|
@required this.onChanged,
|
||||||
this.elevation = 8,
|
this.elevation = 8,
|
||||||
this.style,
|
this.style,
|
||||||
this.iconSize = 24.0,
|
this.iconSize = 24.0,
|
||||||
this.isDense = false,
|
this.isDense = false,
|
||||||
this.isExpanded = false,
|
this.isExpanded = false,
|
||||||
}) : assert(items != null),
|
}) : assert(items == null || value == null || items.where((DropdownMenuItem<T> item) => item.value == value).length == 1),
|
||||||
assert(value == null || items.where((DropdownMenuItem<T> item) => item.value == value).length == 1),
|
|
||||||
super(key: key);
|
super(key: key);
|
||||||
|
|
||||||
/// The list of possible items to select among.
|
/// The list of possible items to select among.
|
||||||
@ -522,6 +524,11 @@ class DropdownButton<T> extends StatefulWidget {
|
|||||||
/// Displayed if [value] is null.
|
/// Displayed if [value] is null.
|
||||||
final Widget hint;
|
final Widget hint;
|
||||||
|
|
||||||
|
/// A message to show when the dropdown is disabled.
|
||||||
|
///
|
||||||
|
/// Displayed if [items] or [onChanged] is null.
|
||||||
|
final Widget disabledHint;
|
||||||
|
|
||||||
/// Called when the user selects an item.
|
/// Called when the user selects an item.
|
||||||
final ValueChanged<T> onChanged;
|
final ValueChanged<T> onChanged;
|
||||||
|
|
||||||
@ -600,6 +607,10 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _updateSelectedIndex() {
|
void _updateSelectedIndex() {
|
||||||
|
if (!_enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
assert(widget.value == null ||
|
assert(widget.value == null ||
|
||||||
widget.items.where((DropdownMenuItem<T> item) => item.value == widget.value).length == 1);
|
widget.items.where((DropdownMenuItem<T> item) => item.value == widget.value).length == 1);
|
||||||
_selectedIndex = null;
|
_selectedIndex = null;
|
||||||
@ -650,6 +661,25 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
|
|||||||
return math.max(_textStyle.fontSize, math.max(widget.iconSize, _kDenseButtonHeight));
|
return math.max(_textStyle.fontSize, math.max(widget.iconSize, _kDenseButtonHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color get _downArrowColor {
|
||||||
|
// These colors are not defined in the Material Design spec.
|
||||||
|
if (_enabled) {
|
||||||
|
if (Theme.of(context).brightness == Brightness.light) {
|
||||||
|
return Colors.grey.shade700;
|
||||||
|
} else {
|
||||||
|
return Colors.white70;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Theme.of(context).brightness == Brightness.light) {
|
||||||
|
return Colors.grey.shade400;
|
||||||
|
} else {
|
||||||
|
return Colors.white10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get _enabled => widget.items != null && widget.items.isNotEmpty && widget.onChanged != null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
assert(debugCheckHasMaterial(context));
|
assert(debugCheckHasMaterial(context));
|
||||||
@ -657,14 +687,16 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
|
|||||||
|
|
||||||
// The width of the button and the menu are defined by the widest
|
// The width of the button and the menu are defined by the widest
|
||||||
// item and the width of the hint.
|
// item and the width of the hint.
|
||||||
final List<Widget> items = List<Widget>.from(widget.items);
|
final List<Widget> items = _enabled ? List<Widget>.from(widget.items) : <Widget>[];
|
||||||
int hintIndex;
|
int hintIndex;
|
||||||
if (widget.hint != null) {
|
if (widget.hint != null || (!_enabled && widget.disabledHint != null)) {
|
||||||
|
final Widget emplacedHint =
|
||||||
|
_enabled ? widget.hint : DropdownMenuItem<Widget>(child: widget.disabledHint ?? widget.hint);
|
||||||
hintIndex = items.length;
|
hintIndex = items.length;
|
||||||
items.add(DefaultTextStyle(
|
items.add(DefaultTextStyle(
|
||||||
style: _textStyle.copyWith(color: Theme.of(context).hintColor),
|
style: _textStyle.copyWith(color: Theme.of(context).hintColor),
|
||||||
child: IgnorePointer(
|
child: IgnorePointer(
|
||||||
child: widget.hint,
|
child: emplacedHint,
|
||||||
ignoringSemantics: false,
|
ignoringSemantics: false,
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
@ -674,10 +706,10 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
|
|||||||
? _kAlignedButtonPadding
|
? _kAlignedButtonPadding
|
||||||
: _kUnalignedButtonPadding;
|
: _kUnalignedButtonPadding;
|
||||||
|
|
||||||
// If value is null (then _selectedIndex is null) then we display
|
// If value is null (then _selectedIndex is null) or if disabled then we
|
||||||
// the hint or nothing at all.
|
// display the hint or nothing at all.
|
||||||
final IndexedStack innerItemsWidget = IndexedStack(
|
final IndexedStack innerItemsWidget = IndexedStack(
|
||||||
index: _selectedIndex ?? hintIndex,
|
index: _enabled ? (_selectedIndex ?? hintIndex) : hintIndex,
|
||||||
alignment: AlignmentDirectional.centerStart,
|
alignment: AlignmentDirectional.centerStart,
|
||||||
children: items,
|
children: items,
|
||||||
);
|
);
|
||||||
@ -694,8 +726,7 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
|
|||||||
widget.isExpanded ? Expanded(child: innerItemsWidget) : innerItemsWidget,
|
widget.isExpanded ? Expanded(child: innerItemsWidget) : innerItemsWidget,
|
||||||
Icon(Icons.arrow_drop_down,
|
Icon(Icons.arrow_drop_down,
|
||||||
size: widget.iconSize,
|
size: widget.iconSize,
|
||||||
// These colors are not defined in the Material Design spec.
|
color: _downArrowColor,
|
||||||
color: Theme.of(context).brightness == Brightness.light ? Colors.grey.shade700 : Colors.white70
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -725,7 +756,7 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
|
|||||||
return Semantics(
|
return Semantics(
|
||||||
button: true,
|
button: true,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: _handleTap,
|
onTap: _enabled ? _handleTap : null,
|
||||||
behavior: HitTestBehavior.opaque,
|
behavior: HitTestBehavior.opaque,
|
||||||
child: result
|
child: result
|
||||||
),
|
),
|
||||||
|
@ -13,6 +13,7 @@ import 'package:flutter/rendering.dart';
|
|||||||
import '../widgets/semantics_tester.dart';
|
import '../widgets/semantics_tester.dart';
|
||||||
|
|
||||||
const List<String> menuItems = <String>['one', 'two', 'three', 'four'];
|
const List<String> menuItems = <String>['one', 'two', 'three', 'four'];
|
||||||
|
final ValueChanged<String> onChanged = (_) {};
|
||||||
|
|
||||||
final Type dropdownButtonType = DropdownButton<String>(
|
final Type dropdownButtonType = DropdownButton<String>(
|
||||||
onChanged: (_) { },
|
onChanged: (_) { },
|
||||||
@ -26,6 +27,7 @@ Widget buildFrame({
|
|||||||
bool isDense = false,
|
bool isDense = false,
|
||||||
bool isExpanded = false,
|
bool isExpanded = false,
|
||||||
Widget hint,
|
Widget hint,
|
||||||
|
Widget disabledHint,
|
||||||
List<String> items = menuItems,
|
List<String> items = menuItems,
|
||||||
Alignment alignment = Alignment.center,
|
Alignment alignment = Alignment.center,
|
||||||
TextDirection textDirection = TextDirection.ltr,
|
TextDirection textDirection = TextDirection.ltr,
|
||||||
@ -40,10 +42,11 @@ Widget buildFrame({
|
|||||||
key: buttonKey,
|
key: buttonKey,
|
||||||
value: value,
|
value: value,
|
||||||
hint: hint,
|
hint: hint,
|
||||||
|
disabledHint: disabledHint,
|
||||||
onChanged: onChanged,
|
onChanged: onChanged,
|
||||||
isDense: isDense,
|
isDense: isDense,
|
||||||
isExpanded: isExpanded,
|
isExpanded: isExpanded,
|
||||||
items: items.map<DropdownMenuItem<String>>((String item) {
|
items: items == null ? null : items.map<DropdownMenuItem<String>>((String item) {
|
||||||
return DropdownMenuItem<String>(
|
return DropdownMenuItem<String>(
|
||||||
key: ValueKey<String>(item),
|
key: ValueKey<String>(item),
|
||||||
value: item,
|
value: item,
|
||||||
@ -115,7 +118,7 @@ bool sameGeometry(RenderBox box1, RenderBox box2) {
|
|||||||
void main() {
|
void main() {
|
||||||
testWidgets('Default dropdown golden', (WidgetTester tester) async {
|
testWidgets('Default dropdown golden', (WidgetTester tester) async {
|
||||||
final Key buttonKey = UniqueKey();
|
final Key buttonKey = UniqueKey();
|
||||||
Widget build() => buildFrame(buttonKey: buttonKey, value: 'two');
|
Widget build() => buildFrame(buttonKey: buttonKey, value: 'two', onChanged: onChanged);
|
||||||
await tester.pumpWidget(build());
|
await tester.pumpWidget(build());
|
||||||
final Finder buttonFinder = find.byKey(buttonKey);
|
final Finder buttonFinder = find.byKey(buttonKey);
|
||||||
assert(tester.renderObject(buttonFinder).attached);
|
assert(tester.renderObject(buttonFinder).attached);
|
||||||
@ -128,7 +131,7 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Expanded dropdown golden', (WidgetTester tester) async {
|
testWidgets('Expanded dropdown golden', (WidgetTester tester) async {
|
||||||
final Key buttonKey = UniqueKey();
|
final Key buttonKey = UniqueKey();
|
||||||
Widget build() => buildFrame(buttonKey: buttonKey, value: 'two', isExpanded: true);
|
Widget build() => buildFrame(buttonKey: buttonKey, value: 'two', isExpanded: true, onChanged: onChanged);
|
||||||
await tester.pumpWidget(build());
|
await tester.pumpWidget(build());
|
||||||
final Finder buttonFinder = find.byKey(buttonKey);
|
final Finder buttonFinder = find.byKey(buttonKey);
|
||||||
assert(tester.renderObject(buttonFinder).attached);
|
assert(tester.renderObject(buttonFinder).attached);
|
||||||
@ -326,7 +329,7 @@ void main() {
|
|||||||
final Key buttonKey = UniqueKey();
|
final Key buttonKey = UniqueKey();
|
||||||
const String value = 'two';
|
const String value = 'two';
|
||||||
|
|
||||||
Widget build() => buildFrame(buttonKey: buttonKey, value: value, textDirection: textDirection);
|
Widget build() => buildFrame(buttonKey: buttonKey, value: value, textDirection: textDirection, onChanged: onChanged);
|
||||||
|
|
||||||
await tester.pumpWidget(build());
|
await tester.pumpWidget(build());
|
||||||
final RenderBox buttonBox = tester.renderObject(find.byKey(buttonKey));
|
final RenderBox buttonBox = tester.renderObject(find.byKey(buttonKey));
|
||||||
@ -371,7 +374,7 @@ void main() {
|
|||||||
testWidgets('Arrow icon aligns with the edge of button when expanded', (WidgetTester tester) async {
|
testWidgets('Arrow icon aligns with the edge of button when expanded', (WidgetTester tester) async {
|
||||||
final Key buttonKey = UniqueKey();
|
final Key buttonKey = UniqueKey();
|
||||||
|
|
||||||
Widget build() => buildFrame(buttonKey: buttonKey, value: 'two', isExpanded: true);
|
Widget build() => buildFrame(buttonKey: buttonKey, value: 'two', isExpanded: true, onChanged: onChanged);
|
||||||
|
|
||||||
await tester.pumpWidget(build());
|
await tester.pumpWidget(build());
|
||||||
final RenderBox buttonBox = tester.renderObject(find.byKey(buttonKey));
|
final RenderBox buttonBox = tester.renderObject(find.byKey(buttonKey));
|
||||||
@ -389,7 +392,7 @@ void main() {
|
|||||||
final Key buttonKey = UniqueKey();
|
final Key buttonKey = UniqueKey();
|
||||||
const String value = 'two';
|
const String value = 'two';
|
||||||
|
|
||||||
Widget build() => buildFrame(buttonKey: buttonKey, value: value, isDense: true);
|
Widget build() => buildFrame(buttonKey: buttonKey, value: value, isDense: true, onChanged: onChanged);
|
||||||
|
|
||||||
await tester.pumpWidget(build());
|
await tester.pumpWidget(build());
|
||||||
final RenderBox buttonBox = tester.renderObject(find.byKey(buttonKey));
|
final RenderBox buttonBox = tester.renderObject(find.byKey(buttonKey));
|
||||||
@ -428,7 +431,8 @@ void main() {
|
|||||||
await tester.pumpWidget(buildFrame(
|
await tester.pumpWidget(buildFrame(
|
||||||
buttonKey: buttonKey,
|
buttonKey: buttonKey,
|
||||||
value: null, // nothing selected
|
value: null, // nothing selected
|
||||||
items: List<String>.generate(/*length=*/ 100, (int index) => index.toString())
|
items: List<String>.generate(/*length=*/ 100, (int index) => index.toString()),
|
||||||
|
onChanged: onChanged,
|
||||||
));
|
));
|
||||||
await tester.tap(find.byKey(buttonKey));
|
await tester.tap(find.byKey(buttonKey));
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
@ -455,7 +459,8 @@ void main() {
|
|||||||
await tester.pumpWidget(buildFrame(
|
await tester.pumpWidget(buildFrame(
|
||||||
buttonKey: buttonKey,
|
buttonKey: buttonKey,
|
||||||
value: '50',
|
value: '50',
|
||||||
items: List<String>.generate(/*length=*/ 100, (int index) => index.toString())
|
items: List<String>.generate(/*length=*/ 100, (int index) => index.toString()),
|
||||||
|
onChanged: onChanged,
|
||||||
));
|
));
|
||||||
final RenderBox buttonBox = tester.renderObject(find.byKey(buttonKey));
|
final RenderBox buttonBox = tester.renderObject(find.byKey(buttonKey));
|
||||||
await tester.tap(find.byKey(buttonKey));
|
await tester.tap(find.byKey(buttonKey));
|
||||||
@ -477,7 +482,7 @@ void main() {
|
|||||||
final Key buttonKey = UniqueKey();
|
final Key buttonKey = UniqueKey();
|
||||||
String value;
|
String value;
|
||||||
|
|
||||||
Widget build() => buildFrame(buttonKey: buttonKey, value: value);
|
Widget build() => buildFrame(buttonKey: buttonKey, value: value, onChanged: onChanged);
|
||||||
|
|
||||||
await tester.pumpWidget(build());
|
await tester.pumpWidget(build());
|
||||||
final RenderBox buttonBoxNullValue = tester.renderObject(find.byKey(buttonKey));
|
final RenderBox buttonBoxNullValue = tester.renderObject(find.byKey(buttonKey));
|
||||||
@ -594,19 +599,19 @@ void main() {
|
|||||||
// so that it fits within the frame.
|
// so that it fits within the frame.
|
||||||
|
|
||||||
await popUpAndDown(
|
await popUpAndDown(
|
||||||
buildFrame(alignment: Alignment.topLeft, value: menuItems.last)
|
buildFrame(alignment: Alignment.topLeft, value: menuItems.last, onChanged: onChanged)
|
||||||
);
|
);
|
||||||
expect(menuRect.topLeft, Offset.zero);
|
expect(menuRect.topLeft, Offset.zero);
|
||||||
expect(menuRect.topRight, Offset(menuRect.width, 0.0));
|
expect(menuRect.topRight, Offset(menuRect.width, 0.0));
|
||||||
|
|
||||||
await popUpAndDown(
|
await popUpAndDown(
|
||||||
buildFrame(alignment: Alignment.topCenter, value: menuItems.last)
|
buildFrame(alignment: Alignment.topCenter, value: menuItems.last, onChanged: onChanged)
|
||||||
);
|
);
|
||||||
expect(menuRect.topLeft, Offset(buttonRect.left, 0.0));
|
expect(menuRect.topLeft, Offset(buttonRect.left, 0.0));
|
||||||
expect(menuRect.topRight, Offset(buttonRect.right, 0.0));
|
expect(menuRect.topRight, Offset(buttonRect.right, 0.0));
|
||||||
|
|
||||||
await popUpAndDown(
|
await popUpAndDown(
|
||||||
buildFrame(alignment: Alignment.topRight, value: menuItems.last)
|
buildFrame(alignment: Alignment.topRight, value: menuItems.last, onChanged: onChanged)
|
||||||
);
|
);
|
||||||
expect(menuRect.topLeft, Offset(800.0 - menuRect.width, 0.0));
|
expect(menuRect.topLeft, Offset(800.0 - menuRect.width, 0.0));
|
||||||
expect(menuRect.topRight, const Offset(800.0, 0.0));
|
expect(menuRect.topRight, const Offset(800.0, 0.0));
|
||||||
@ -616,19 +621,19 @@ void main() {
|
|||||||
// is selected) and shifted horizontally so that it fits within the frame.
|
// is selected) and shifted horizontally so that it fits within the frame.
|
||||||
|
|
||||||
await popUpAndDown(
|
await popUpAndDown(
|
||||||
buildFrame(alignment: Alignment.centerLeft, value: menuItems.first)
|
buildFrame(alignment: Alignment.centerLeft, value: menuItems.first, onChanged: onChanged)
|
||||||
);
|
);
|
||||||
expect(menuRect.topLeft, Offset(0.0, buttonRect.top));
|
expect(menuRect.topLeft, Offset(0.0, buttonRect.top));
|
||||||
expect(menuRect.topRight, Offset(menuRect.width, buttonRect.top));
|
expect(menuRect.topRight, Offset(menuRect.width, buttonRect.top));
|
||||||
|
|
||||||
await popUpAndDown(
|
await popUpAndDown(
|
||||||
buildFrame(alignment: Alignment.center, value: menuItems.first)
|
buildFrame(alignment: Alignment.center, value: menuItems.first, onChanged: onChanged)
|
||||||
);
|
);
|
||||||
expect(menuRect.topLeft, buttonRect.topLeft);
|
expect(menuRect.topLeft, buttonRect.topLeft);
|
||||||
expect(menuRect.topRight, buttonRect.topRight);
|
expect(menuRect.topRight, buttonRect.topRight);
|
||||||
|
|
||||||
await popUpAndDown(
|
await popUpAndDown(
|
||||||
buildFrame(alignment: Alignment.centerRight, value: menuItems.first)
|
buildFrame(alignment: Alignment.centerRight, value: menuItems.first, onChanged: onChanged)
|
||||||
);
|
);
|
||||||
expect(menuRect.topLeft, Offset(800.0 - menuRect.width, buttonRect.top));
|
expect(menuRect.topLeft, Offset(800.0 - menuRect.width, buttonRect.top));
|
||||||
expect(menuRect.topRight, Offset(800.0, buttonRect.top));
|
expect(menuRect.topRight, Offset(800.0, buttonRect.top));
|
||||||
@ -638,26 +643,26 @@ void main() {
|
|||||||
// so that it fits within the frame.
|
// so that it fits within the frame.
|
||||||
|
|
||||||
await popUpAndDown(
|
await popUpAndDown(
|
||||||
buildFrame(alignment: Alignment.bottomLeft, value: menuItems.first)
|
buildFrame(alignment: Alignment.bottomLeft, value: menuItems.first, onChanged: onChanged)
|
||||||
);
|
);
|
||||||
expect(menuRect.bottomLeft, const Offset(0.0, 600.0));
|
expect(menuRect.bottomLeft, const Offset(0.0, 600.0));
|
||||||
expect(menuRect.bottomRight, Offset(menuRect.width, 600.0));
|
expect(menuRect.bottomRight, Offset(menuRect.width, 600.0));
|
||||||
|
|
||||||
await popUpAndDown(
|
await popUpAndDown(
|
||||||
buildFrame(alignment: Alignment.bottomCenter, value: menuItems.first)
|
buildFrame(alignment: Alignment.bottomCenter, value: menuItems.first, onChanged: onChanged)
|
||||||
);
|
);
|
||||||
expect(menuRect.bottomLeft, Offset(buttonRect.left, 600.0));
|
expect(menuRect.bottomLeft, Offset(buttonRect.left, 600.0));
|
||||||
expect(menuRect.bottomRight, Offset(buttonRect.right, 600.0));
|
expect(menuRect.bottomRight, Offset(buttonRect.right, 600.0));
|
||||||
|
|
||||||
await popUpAndDown(
|
await popUpAndDown(
|
||||||
buildFrame(alignment: Alignment.bottomRight, value: menuItems.first)
|
buildFrame(alignment: Alignment.bottomRight, value: menuItems.first, onChanged: onChanged)
|
||||||
);
|
);
|
||||||
expect(menuRect.bottomLeft, Offset(800.0 - menuRect.width, 600.0));
|
expect(menuRect.bottomLeft, Offset(800.0 - menuRect.width, 600.0));
|
||||||
expect(menuRect.bottomRight, const Offset(800.0, 600.0));
|
expect(menuRect.bottomRight, const Offset(800.0, 600.0));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Dropdown menus are dismissed on screen orientation changes', (WidgetTester tester) async {
|
testWidgets('Dropdown menus are dismissed on screen orientation changes', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(buildFrame());
|
await tester.pumpWidget(buildFrame(onChanged: onChanged));
|
||||||
await tester.tap(find.byType(dropdownButtonType));
|
await tester.tap(find.byType(dropdownButtonType));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
expect(find.byType(ListView), findsOneWidget);
|
expect(find.byType(ListView), findsOneWidget);
|
||||||
@ -670,7 +675,7 @@ void main() {
|
|||||||
|
|
||||||
testWidgets('Semantics Tree contains only selected element', (WidgetTester tester) async {
|
testWidgets('Semantics Tree contains only selected element', (WidgetTester tester) async {
|
||||||
final SemanticsTester semantics = SemanticsTester(tester);
|
final SemanticsTester semantics = SemanticsTester(tester);
|
||||||
await tester.pumpWidget(buildFrame(items: menuItems));
|
await tester.pumpWidget(buildFrame(items: menuItems, onChanged: onChanged));
|
||||||
|
|
||||||
expect(semantics, isNot(includesNodeWith(label: menuItems[0])));
|
expect(semantics, isNot(includesNodeWith(label: menuItems[0])));
|
||||||
expect(semantics, includesNodeWith(label: menuItems[1]));
|
expect(semantics, includesNodeWith(label: menuItems[1]));
|
||||||
@ -702,7 +707,7 @@ void main() {
|
|||||||
buttonKey: key,
|
buttonKey: key,
|
||||||
value: 'three',
|
value: 'three',
|
||||||
items: menuItems,
|
items: menuItems,
|
||||||
onChanged: null,
|
onChanged: onChanged,
|
||||||
hint: const Text('test'),
|
hint: const Text('test'),
|
||||||
));
|
));
|
||||||
|
|
||||||
@ -722,6 +727,7 @@ void main() {
|
|||||||
buttonKey: key,
|
buttonKey: key,
|
||||||
value: null,
|
value: null,
|
||||||
items: menuItems,
|
items: menuItems,
|
||||||
|
onChanged: onChanged,
|
||||||
));
|
));
|
||||||
await tester.tap(find.byKey(key));
|
await tester.tap(find.byKey(key));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
@ -778,6 +784,42 @@ void main() {
|
|||||||
semantics.dispose();
|
semantics.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('disabledHint displays on empty items or onChanged', (WidgetTester tester) async {
|
||||||
|
final Key buttonKey = UniqueKey();
|
||||||
|
|
||||||
|
Widget build({List<String> items, ValueChanged<String> onChanged}) => buildFrame(
|
||||||
|
items: items,
|
||||||
|
onChanged: onChanged,
|
||||||
|
buttonKey: buttonKey, value: null,
|
||||||
|
hint: const Text('enabled'),
|
||||||
|
disabledHint: const Text('disabled'));
|
||||||
|
|
||||||
|
// [disabledHint] should display when [items] is null
|
||||||
|
await tester.pumpWidget(build(items: null, onChanged: onChanged));
|
||||||
|
expect(find.text('enabled'), findsNothing);
|
||||||
|
expect(find.text('disabled'), findsOneWidget);
|
||||||
|
|
||||||
|
// [disabledHint] should display when [items] is an empty list.
|
||||||
|
await tester.pumpWidget(build(items: <String>[], onChanged: onChanged));
|
||||||
|
expect(find.text('enabled'), findsNothing);
|
||||||
|
expect(find.text('disabled'), findsOneWidget);
|
||||||
|
|
||||||
|
// [disabledHint] should display when [onChanged] is null
|
||||||
|
await tester.pumpWidget(build(items: menuItems, onChanged: null));
|
||||||
|
expect(find.text('enabled'), findsNothing);
|
||||||
|
expect(find.text('disabled'), findsOneWidget);
|
||||||
|
final RenderBox disabledHintBox = tester.renderObject(find.byKey(buttonKey));
|
||||||
|
|
||||||
|
// A Dropdown button with a disabled hint should be the same size as a
|
||||||
|
// one with a regular enabled hint.
|
||||||
|
await tester.pumpWidget(build(items: menuItems, onChanged: onChanged));
|
||||||
|
expect(find.text('disabled'), findsNothing);
|
||||||
|
expect(find.text('enabled'), findsOneWidget);
|
||||||
|
final RenderBox enabledHintBox = tester.renderObject(find.byKey(buttonKey));
|
||||||
|
expect(enabledHintBox.localToGlobal(Offset.zero), equals(disabledHintBox.localToGlobal(Offset.zero)));
|
||||||
|
expect(enabledHintBox.size, equals(disabledHintBox.size));
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('Dropdown in middle showing middle item', (WidgetTester tester) async {
|
testWidgets('Dropdown in middle showing middle item', (WidgetTester tester) async {
|
||||||
final List<DropdownMenuItem<int>> items =
|
final List<DropdownMenuItem<int>> items =
|
||||||
List<DropdownMenuItem<int>>.generate(100, (int i) =>
|
List<DropdownMenuItem<int>>.generate(100, (int i) =>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user