DropdownButtonFormField<T> constructor
- Key? key,
- required List<
DropdownMenuItem< ? items,T> > - DropdownButtonBuilder? selectedItemBuilder,
- T? value,
- Widget? hint,
- Widget? disabledHint,
- required ValueChanged<
T?> ? onChanged, - VoidCallback? onTap,
- int elevation = 8,
- TextStyle? style,
- Widget? icon,
- Color? iconDisabledColor,
- Color? iconEnabledColor,
- double iconSize = 24.0,
- bool isDense = true,
- bool isExpanded = false,
- double? itemHeight,
- Color? focusColor,
- FocusNode? focusNode,
- bool autofocus = false,
- Color? dropdownColor,
- InputDecoration? decoration,
- FormFieldSetter<
T> ? onSaved, - FormFieldValidator<
T> ? validator, - AutovalidateMode? autovalidateMode,
- bool? enableFeedback,
- AlignmentGeometry alignment = AlignmentDirectional.centerStart,
- BorderRadius? borderRadius,
- EdgeInsetsGeometry? padding,
Creates a DropdownButton widget that is a FormField, wrapped in an InputDecorator.
For a description of the onSaved
, validator
, or autovalidateMode
parameters, see FormField. For the rest (other than decoration
), see
DropdownButton.
Implementation
DropdownButtonFormField({
super.key,
required List<DropdownMenuItem<T>>? items,
DropdownButtonBuilder? selectedItemBuilder,
T? value,
Widget? hint,
Widget? disabledHint,
required this.onChanged,
VoidCallback? onTap,
int elevation = 8,
TextStyle? style,
Widget? icon,
Color? iconDisabledColor,
Color? iconEnabledColor,
double iconSize = 24.0,
bool isDense = true,
bool isExpanded = false,
double? itemHeight,
Color? focusColor,
FocusNode? focusNode,
bool autofocus = false,
Color? dropdownColor,
InputDecoration? decoration,
super.onSaved,
super.validator,
AutovalidateMode? autovalidateMode,
double? menuMaxHeight,
bool? enableFeedback,
AlignmentGeometry alignment = AlignmentDirectional.centerStart,
BorderRadius? borderRadius,
EdgeInsetsGeometry? padding,
// When adding new arguments, consider adding similar arguments to
// DropdownButton.
}) : assert(items == null || items.isEmpty || value == null ||
items.where((DropdownMenuItem<T> item) => item.value == value).length == 1,
"There should be exactly one item with [DropdownButton]'s value: "
'$value. \n'
'Either zero or 2 or more [DropdownMenuItem]s were detected '
'with the same value',
),
assert(itemHeight == null || itemHeight >= kMinInteractiveDimension),
decoration = decoration ?? InputDecoration(focusColor: focusColor),
super(
initialValue: value,
autovalidateMode: autovalidateMode ?? AutovalidateMode.disabled,
builder: (FormFieldState<T> field) {
final _DropdownButtonFormFieldState<T> state = field as _DropdownButtonFormFieldState<T>;
final InputDecoration decorationArg = decoration ?? InputDecoration(focusColor: focusColor);
final InputDecoration effectiveDecoration = decorationArg.applyDefaults(
Theme.of(field.context).inputDecorationTheme,
);
final bool showSelectedItem = items != null && items.where((DropdownMenuItem<T> item) => item.value == state.value).isNotEmpty;
final bool isDropdownEnabled = onChanged != null && items != null && items.isNotEmpty;
// If decoration hintText is provided, use it as the default value for both hint and disabledHint.
final Widget? decorationHint = effectiveDecoration.hintText != null ? Text(effectiveDecoration.hintText!) : null;
final Widget? effectiveHint = hint ?? decorationHint;
final Widget? effectiveDisabledHint = disabledHint ?? effectiveHint;
final bool isHintOrDisabledHintAvailable = isDropdownEnabled
? effectiveHint != null
: effectiveHint != null || effectiveDisabledHint != null;
final bool isEmpty = !showSelectedItem && !isHintOrDisabledHintAvailable;
// An unfocusable Focus widget so that this widget can detect if its
// descendants have focus or not.
return Focus(
canRequestFocus: false,
skipTraversal: true,
child: Builder(builder: (BuildContext context) {
final bool isFocused = Focus.of(context).hasFocus;
late final InputBorder? resolvedBorder = switch ((
enabled: effectiveDecoration.enabled,
focused: isFocused,
error: effectiveDecoration.errorText != null,
)) {
(enabled: _, focused: true, error: true) => effectiveDecoration.focusedErrorBorder,
(enabled: _, focused: _, error: true) => effectiveDecoration.errorBorder,
(enabled: _, focused: true, error: _) => effectiveDecoration.focusedBorder,
(enabled: true, focused: _, error: _) => effectiveDecoration.enabledBorder,
(enabled: false, focused: _, error: _) => effectiveDecoration.border,
};
return DropdownButtonHideUnderline(
child: DropdownButton<T>._formField(
items: items,
selectedItemBuilder: selectedItemBuilder,
value: state.value,
hint: effectiveHint,
disabledHint: effectiveDisabledHint,
onChanged: onChanged == null ? null : state.didChange,
onTap: onTap,
elevation: elevation,
style: style,
icon: icon,
iconDisabledColor: iconDisabledColor,
iconEnabledColor: iconEnabledColor,
iconSize: iconSize,
isDense: isDense,
isExpanded: isExpanded,
itemHeight: itemHeight,
focusColor: focusColor,
focusNode: focusNode,
autofocus: autofocus,
dropdownColor: dropdownColor,
menuMaxHeight: menuMaxHeight,
enableFeedback: enableFeedback,
alignment: alignment,
borderRadius: borderRadius ?? switch (resolvedBorder) {
final OutlineInputBorder border => border.borderRadius,
final UnderlineInputBorder border => border.borderRadius,
_ => null,
},
// Clear the decoration hintText because DropdownButton has its own hint logic.
inputDecoration: effectiveDecoration.copyWith(
errorText: field.errorText,
hintText: effectiveDecoration.hintText != null ? '' : null,
),
isEmpty: isEmpty,
isFocused: isFocused,
padding: padding,
),
);
}),
);
},
);