DropdownButtonFormField<T> constructor

DropdownButtonFormField<T>({
  1. Key? key,
  2. required List<DropdownMenuItem<T>>? items,
  3. DropdownButtonBuilder? selectedItemBuilder,
  4. T? value,
  5. Widget? hint,
  6. Widget? disabledHint,
  7. required ValueChanged<T?>? onChanged,
  8. VoidCallback? onTap,
  9. int elevation = 8,
  10. TextStyle? style,
  11. Widget? icon,
  12. Color? iconDisabledColor,
  13. Color? iconEnabledColor,
  14. double iconSize = 24.0,
  15. bool isDense = true,
  16. bool isExpanded = false,
  17. double? itemHeight,
  18. Color? focusColor,
  19. FocusNode? focusNode,
  20. bool autofocus = false,
  21. Color? dropdownColor,
  22. InputDecoration? decoration,
  23. FormFieldSetter<T>? onSaved,
  24. FormFieldValidator<T>? validator,
  25. AutovalidateMode? autovalidateMode,
  26. double? menuMaxHeight,
  27. bool? enableFeedback,
  28. AlignmentGeometry alignment = AlignmentDirectional.centerStart,
  29. BorderRadius? borderRadius,
  30. 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,
                ),
              );
            }),
          );
        },
      );