Skip to content

Commit 734ddd3

Browse files
author
Shi-Hao Hong
authored
Make DropdownButton's disabledHint and hint behavior consistent (flutter#42479)
* Fix DropdownButton disabledHint behavior * Fix hint behavior when selectedItemBuilder is null * Improve variable names, some formatting updates * Create _DropdownMenuItemContainer widget * Improve API docs to be consistent with hint/disabledHint actual behavior
1 parent 109f255 commit 734ddd3

File tree

2 files changed

+430
-34
lines changed

2 files changed

+430
-34
lines changed

packages/flutter/lib/src/material/dropdown.dart

Lines changed: 57 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -537,17 +537,15 @@ class _RenderMenuItem extends RenderProxyBox {
537537
}
538538
}
539539

540-
/// An item in a menu created by a [DropdownButton].
541-
///
542-
/// The type `T` is the type of the value the entry represents. All the entries
543-
/// in a given menu must represent values with consistent types.
544-
class DropdownMenuItem<T> extends StatelessWidget {
540+
// The container widget for a menu item created by a [DropdownButton]. It
541+
// provides the default configuration for [DropdownMenuItem]s, as well as a
542+
// [DropdownButton]'s hint and disabledHint widgets.
543+
class _DropdownMenuItemContainer extends StatelessWidget {
545544
/// Creates an item for a dropdown menu.
546545
///
547546
/// The [child] argument is required.
548-
const DropdownMenuItem({
547+
const _DropdownMenuItemContainer({
549548
Key key,
550-
this.value,
551549
@required this.child,
552550
}) : assert(child != null),
553551
super(key: key);
@@ -557,11 +555,6 @@ class DropdownMenuItem<T> extends StatelessWidget {
557555
/// Typically a [Text] widget.
558556
final Widget child;
559557

560-
/// The value to return if the user selects this menu item.
561-
///
562-
/// Eventually returned in a call to [DropdownButton.onChanged].
563-
final T value;
564-
565558
@override
566559
Widget build(BuildContext context) {
567560
return Container(
@@ -572,6 +565,27 @@ class DropdownMenuItem<T> extends StatelessWidget {
572565
}
573566
}
574567

568+
/// An item in a menu created by a [DropdownButton].
569+
///
570+
/// The type `T` is the type of the value the entry represents. All the entries
571+
/// in a given menu must represent values with consistent types.
572+
class DropdownMenuItem<T> extends _DropdownMenuItemContainer {
573+
/// Creates an item for a dropdown menu.
574+
///
575+
/// The [child] argument is required.
576+
const DropdownMenuItem({
577+
Key key,
578+
this.value,
579+
@required Widget child,
580+
}) : assert(child != null),
581+
super(key: key, child: child);
582+
583+
/// The value to return if the user selects this menu item.
584+
///
585+
/// Eventually returned in a call to [DropdownButton.onChanged].
586+
final T value;
587+
}
588+
575589
/// An inherited widget that causes any descendant [DropdownButton]
576590
/// widgets to not include their regular underline.
577591
///
@@ -658,7 +672,9 @@ class DropdownButtonHideUnderline extends InheritedWidget {
658672
/// If the [onChanged] callback is null or the list of [items] is null
659673
/// then the dropdown button will be disabled, i.e. its arrow will be
660674
/// displayed in grey and it will not respond to input. A disabled button
661-
/// will display the [disabledHint] widget if it is non-null.
675+
/// will display the [disabledHint] widget if it is non-null. However, if
676+
/// [disabledHint] is null and [hint] is non-null, the [hint] widget will
677+
/// instead be displayed.
662678
///
663679
/// Requires one of its ancestors to be a [Material] widget.
664680
///
@@ -676,6 +692,8 @@ class DropdownButton<T> extends StatefulWidget {
676692
/// must be equal to one of the [DropDownMenuItem] values. If [items] or
677693
/// [onChanged] is null, the button will be disabled, the down arrow
678694
/// will be greyed out, and the [disabledHint] will be shown (if provided).
695+
/// If [disabledHint] is null and [hint] is non-null, [hint] will instead be
696+
/// shown.
679697
///
680698
/// The [elevation] and [iconSize] arguments must not be null (they both have
681699
/// defaults, so do not need to be specified). The boolean [isDense] and
@@ -715,20 +733,28 @@ class DropdownButton<T> extends StatefulWidget {
715733
/// If the [onChanged] callback is null or the list of items is null
716734
/// then the dropdown button will be disabled, i.e. its arrow will be
717735
/// displayed in grey and it will not respond to input. A disabled button
718-
/// will display the [disabledHint] widget if it is non-null.
736+
/// will display the [disabledHint] widget if it is non-null. If
737+
/// [disabledHint] is also null but [hint] is non-null, [hint] will instead
738+
/// be displayed.
719739
final List<DropdownMenuItem<T>> items;
720740

721-
/// The value of the currently selected [DropdownMenuItem], or null if no
722-
/// item has been selected. If `value` is null then the menu is popped up as
723-
/// if the first item were selected.
741+
/// The value of the currently selected [DropdownMenuItem].
742+
///
743+
/// If [value] is null and [hint] is non-null, the [hint] widget is
744+
/// displayed as a placeholder for the dropdown button's value.
724745
final T value;
725746

726-
/// A placeholder widget that is displayed if no item is selected, i.e. if [value] is null.
747+
/// A placeholder widget that is displayed by the dropdown button.
748+
///
749+
/// If [value] is null, this widget is displayed as a placeholder for
750+
/// the dropdown button's value. This widget is also displayed if the button
751+
/// is disabled ([items] or [onChanged] is null) and [disabledHint] is null.
727752
final Widget hint;
728753

729754
/// A message to show when the dropdown is disabled.
730755
///
731-
/// Displayed if [items] or [onChanged] is null.
756+
/// Displayed if [items] or [onChanged] is null. If [hint] is non-null and
757+
/// [disabledHint] is null, the [hint] widget will be displayed instead.
732758
final Widget disabledHint;
733759

734760
/// {@template flutter.material.dropdownButton.onChanged}
@@ -737,7 +763,9 @@ class DropdownButton<T> extends StatefulWidget {
737763
/// If the [onChanged] callback is null or the list of [items] is null
738764
/// then the dropdown button will be disabled, i.e. its arrow will be
739765
/// displayed in grey and it will not respond to input. A disabled button
740-
/// will display the [disabledHint] widget if it is non-null.
766+
/// will display the [disabledHint] widget if it is non-null. If
767+
/// [disabledHint] is also null but [hint] is non-null, [hint] will instead
768+
/// be displayed.
741769
/// {@endtemplate}
742770
final ValueChanged<T> onChanged;
743771

@@ -1113,28 +1141,25 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
11131141
if (_enabled) {
11141142
items = widget.selectedItemBuilder == null
11151143
? List<Widget>.from(widget.items)
1116-
: widget.selectedItemBuilder(context).map<Widget>((Widget item) {
1117-
return Container(
1118-
constraints: const BoxConstraints(minHeight: _kMenuItemHeight),
1119-
alignment: AlignmentDirectional.centerStart,
1120-
child: item,
1121-
);
1122-
}).toList();
1144+
: widget.selectedItemBuilder(context);
11231145
} else {
1124-
items = <Widget>[];
1146+
items = widget.selectedItemBuilder == null
1147+
? <Widget>[]
1148+
: widget.selectedItemBuilder(context);
11251149
}
11261150

11271151
int hintIndex;
11281152
if (widget.hint != null || (!_enabled && widget.disabledHint != null)) {
1129-
final Widget emplacedHint = _enabled
1130-
? widget.hint
1131-
: DropdownMenuItem<Widget>(child: widget.disabledHint ?? widget.hint);
1153+
Widget displayedHint = _enabled ? widget.hint : widget.disabledHint ?? widget.hint;
1154+
if (widget.selectedItemBuilder == null)
1155+
displayedHint = _DropdownMenuItemContainer(child: displayedHint);
1156+
11321157
hintIndex = items.length;
11331158
items.add(DefaultTextStyle(
11341159
style: _textStyle.copyWith(color: Theme.of(context).hintColor),
11351160
child: IgnorePointer(
1136-
child: emplacedHint,
11371161
ignoringSemantics: false,
1162+
child: displayedHint,
11381163
),
11391164
));
11401165
}

0 commit comments

Comments
 (0)