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

Make DropdownButton's disabledHint and hint behavior consistent (#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
parent 109f2558
......@@ -537,17 +537,15 @@ class _RenderMenuItem extends RenderProxyBox {
}
}
/// An item in a menu created by a [DropdownButton].
///
/// The type `T` is the type of the value the entry represents. All the entries
/// in a given menu must represent values with consistent types.
class DropdownMenuItem<T> extends StatelessWidget {
// The container widget for a menu item created by a [DropdownButton]. It
// provides the default configuration for [DropdownMenuItem]s, as well as a
// [DropdownButton]'s hint and disabledHint widgets.
class _DropdownMenuItemContainer extends StatelessWidget {
/// Creates an item for a dropdown menu.
///
/// The [child] argument is required.
const DropdownMenuItem({
const _DropdownMenuItemContainer({
Key key,
this.value,
@required this.child,
}) : assert(child != null),
super(key: key);
......@@ -557,11 +555,6 @@ class DropdownMenuItem<T> extends StatelessWidget {
/// Typically a [Text] widget.
final Widget child;
/// The value to return if the user selects this menu item.
///
/// Eventually returned in a call to [DropdownButton.onChanged].
final T value;
@override
Widget build(BuildContext context) {
return Container(
......@@ -572,6 +565,27 @@ class DropdownMenuItem<T> extends StatelessWidget {
}
}
/// An item in a menu created by a [DropdownButton].
///
/// The type `T` is the type of the value the entry represents. All the entries
/// in a given menu must represent values with consistent types.
class DropdownMenuItem<T> extends _DropdownMenuItemContainer {
/// Creates an item for a dropdown menu.
///
/// The [child] argument is required.
const DropdownMenuItem({
Key key,
this.value,
@required Widget child,
}) : assert(child != null),
super(key: key, child: child);
/// The value to return if the user selects this menu item.
///
/// Eventually returned in a call to [DropdownButton.onChanged].
final T value;
}
/// An inherited widget that causes any descendant [DropdownButton]
/// widgets to not include their regular underline.
///
......@@ -658,7 +672,9 @@ class DropdownButtonHideUnderline extends InheritedWidget {
/// If the [onChanged] callback is null or the list of [items] is null
/// then the dropdown button will be disabled, i.e. its arrow will be
/// displayed in grey and it will not respond to input. A disabled button
/// will display the [disabledHint] widget if it is non-null.
/// will display the [disabledHint] widget if it is non-null. However, if
/// [disabledHint] is null and [hint] is non-null, the [hint] widget will
/// instead be displayed.
///
/// Requires one of its ancestors to be a [Material] widget.
///
......@@ -676,6 +692,8 @@ class DropdownButton<T> extends StatefulWidget {
/// must be equal to one of the [DropDownMenuItem] values. If [items] or
/// [onChanged] is null, the button will be disabled, the down arrow
/// will be greyed out, and the [disabledHint] will be shown (if provided).
/// If [disabledHint] is null and [hint] is non-null, [hint] will instead be
/// shown.
///
/// The [elevation] and [iconSize] arguments must not be null (they both have
/// defaults, so do not need to be specified). The boolean [isDense] and
......@@ -715,20 +733,28 @@ class DropdownButton<T> extends StatefulWidget {
/// If the [onChanged] callback is null or the list of items is null
/// then the dropdown button will be disabled, i.e. its arrow will be
/// displayed in grey and it will not respond to input. A disabled button
/// will display the [disabledHint] widget if it is non-null.
/// will display the [disabledHint] widget if it is non-null. If
/// [disabledHint] is also null but [hint] is non-null, [hint] will instead
/// be displayed.
final List<DropdownMenuItem<T>> items;
/// The value of the currently selected [DropdownMenuItem], or null if no
/// item has been selected. If `value` is null then the menu is popped up as
/// if the first item were selected.
/// The value of the currently selected [DropdownMenuItem].
///
/// If [value] is null and [hint] is non-null, the [hint] widget is
/// displayed as a placeholder for the dropdown button's value.
final T value;
/// A placeholder widget that is displayed if no item is selected, i.e. if [value] is null.
/// A placeholder widget that is displayed by the dropdown button.
///
/// If [value] is null, this widget is displayed as a placeholder for
/// the dropdown button's value. This widget is also displayed if the button
/// is disabled ([items] or [onChanged] is null) and [disabledHint] is null.
final Widget hint;
/// A message to show when the dropdown is disabled.
///
/// Displayed if [items] or [onChanged] is null.
/// Displayed if [items] or [onChanged] is null. If [hint] is non-null and
/// [disabledHint] is null, the [hint] widget will be displayed instead.
final Widget disabledHint;
/// {@template flutter.material.dropdownButton.onChanged}
......@@ -737,7 +763,9 @@ class DropdownButton<T> extends StatefulWidget {
/// If the [onChanged] callback is null or the list of [items] is null
/// then the dropdown button will be disabled, i.e. its arrow will be
/// displayed in grey and it will not respond to input. A disabled button
/// will display the [disabledHint] widget if it is non-null.
/// will display the [disabledHint] widget if it is non-null. If
/// [disabledHint] is also null but [hint] is non-null, [hint] will instead
/// be displayed.
/// {@endtemplate}
final ValueChanged<T> onChanged;
......@@ -1113,28 +1141,25 @@ class _DropdownButtonState<T> extends State<DropdownButton<T>> with WidgetsBindi
if (_enabled) {
items = widget.selectedItemBuilder == null
? List<Widget>.from(widget.items)
: widget.selectedItemBuilder(context).map<Widget>((Widget item) {
return Container(
constraints: const BoxConstraints(minHeight: _kMenuItemHeight),
alignment: AlignmentDirectional.centerStart,
child: item,
);
}).toList();
: widget.selectedItemBuilder(context);
} else {
items = <Widget>[];
items = widget.selectedItemBuilder == null
? <Widget>[]
: widget.selectedItemBuilder(context);
}
int hintIndex;
if (widget.hint != null || (!_enabled && widget.disabledHint != null)) {
final Widget emplacedHint = _enabled
? widget.hint
: DropdownMenuItem<Widget>(child: widget.disabledHint ?? widget.hint);
Widget displayedHint = _enabled ? widget.hint : widget.disabledHint ?? widget.hint;
if (widget.selectedItemBuilder == null)
displayedHint = _DropdownMenuItemContainer(child: displayedHint);
hintIndex = items.length;
items.add(DefaultTextStyle(
style: _textStyle.copyWith(color: Theme.of(context).hintColor),
child: IgnorePointer(
child: emplacedHint,
ignoringSemantics: false,
child: displayedHint,
),
));
}
......
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