import 'package:baseproject/assets/images.dart'; import 'package:baseproject/core/components/constants_widget.dart'; import 'package:baseproject/core/components/form/form_builder_field.dart'; import 'package:baseproject/core/components/index.dart'; import 'package:baseproject/core/theme/custom_color.dart'; import 'package:baseproject/core/theme/text_style.dart'; import 'package:collection/collection.dart' show IterableExtension; import 'package:flutter/material.dart'; /// Field for Dropdown button class CustomSelect extends FormBuilderField { /// The list of items the user can select. /// /// 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. If /// [disabledHint] is also null but [hint] is non-null, [hint] will instead /// be displayed. final List> items; /// 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. If [hint] is non-null and /// [disabledHint] is null, the [hint] widget will be displayed instead. final Widget? disabledHint; /// Called when the dropdown button is tapped. /// /// This is distinct from [onChanged], which is called when the user /// selects an item from the dropdown. /// /// The callback will not be invoked if the dropdown button is disabled. final VoidCallback? onTap; /// A builder to customize the dropdown buttons corresponding to the /// [DropdownMenuItem]s in [items]. /// /// When a [DropdownMenuItem] is selected, the widget that will be displayed /// from the list corresponds to the [DropdownMenuItem] of the same index /// in [items]. /// /// {@tool dartpad --template=stateful_widget_scaffold} /// /// This sample shows a `DropdownButton` with a button with [Text] that /// corresponds to but is unique from [DropdownMenuItem]. /// /// If this callback is null, the [DropdownMenuItem] from [items] /// that matches [value] will be displayed. final DropdownButtonBuilder? selectedItemBuilder; /// The z-coordinate at which to place the menu when open. /// /// The following elevations have defined shadows: 1, 2, 3, 4, 6, 8, 9, 12, /// 16, and 24. See [kElevationToShadow]. /// /// Defaults to 8, the appropriate elevation for dropdown buttons. final int elevation; /// {@end-tool} /// /// Defaults to the [TextTheme.subtitle1] value of the current /// [ThemeData.textTheme] of the current [Theme]. final TextStyle? style; /// The widget to use for the drop-down button's icon. /// /// Defaults to an [Icon] with the [Icons.arrow_drop_down] glyph. final Widget? icon; /// The color of any [Icon] descendant of [icon] if this button is disabled, /// i.e. if [onChanged] is null. /// /// Defaults to [Colors.grey.shade400] when the theme's /// [ThemeData.brightness] is [Brightness.light] and to /// [Colors.white10] when it is [Brightness.dark] final Color? iconDisabledColor; /// The color of any [Icon] descendant of [icon] if this button is enabled, /// i.e. if [onChanged] is defined. /// /// Defaults to [Colors.grey.shade700] when the theme's /// [ThemeData.brightness] is [Brightness.light] and to /// [Colors.white70] when it is [Brightness.dark] final Color? iconEnabledColor; /// The size to use for the drop-down button's down arrow icon button. /// /// Defaults to 24.0. final double iconSize; /// Reduce the button's height. /// /// By default this button's height is the same as its menu items' heights. /// If isDense is true, the button's height is reduced by about half. This /// can be useful when the button is embedded in a container that adds /// its own decorations, like [InputDecorator]. final bool isDense; /// Set the dropdown's inner contents to horizontally fill its parent. /// /// By default this button's inner width is the minimum size of its contents. /// If [isExpanded] is true, the inner width is expanded to fill its /// surrounding container. final bool isExpanded; /// If null, then the menu item heights will vary according to each menu item's /// intrinsic height. /// /// The default value is [kMinInteractiveDimension], which is also the minimum /// height for menu items. /// /// If this value is null and there isn't enough vertical room for the menu, /// then the menu's initial scroll offset may not align the selected item with /// the dropdown button. That's because, in this case, the initial scroll /// offset is computed as if all of the menu item heights were /// [kMinInteractiveDimension]. final double itemHeight; /// The color for the button's [Material] when it has the input focus. final Color? focusColor; /// {@macro flutter.widgets.Focus.autofocus} final bool autofocus; /// The background color of the dropdown. /// /// If it is not provided, the theme's [ThemeData.canvasColor] will be used /// instead. final Color? dropdownColor; final bool allowClear; final Widget clearIcon; /// Creates field for Dropdown button CustomSelect({ Key? key, //From Super String name = "select", FormFieldValidator? validator, T? initialValue, InputDecoration decoration = const InputDecoration(), ValueChanged? onChanged, ValueTransformer? valueTransformer, bool enabled = true, FormFieldSetter? onSaved, AutovalidateMode autovalidateMode = AutovalidateMode.disabled, VoidCallback? onReset, FocusNode? focusNode, required this.items, this.isExpanded = true, this.isDense = true, this.elevation = 8, this.iconSize = 24.0, this.hint, this.style, this.disabledHint, this.icon, this.iconDisabledColor, this.iconEnabledColor, this.allowClear = false, this.clearIcon = const Icon( Icons.close, size: 18, color: CustomColor.textGray, ), this.onTap, this.autofocus = false, this.dropdownColor, this.focusColor, this.itemHeight = kMinInteractiveDimension, this.selectedItemBuilder, }) : /*: assert(allowClear == true || clearIcon != null)*/ super( key: key, initialValue: initialValue, name: name, validator: validator, valueTransformer: valueTransformer, onChanged: onChanged, autovalidateMode: autovalidateMode, onSaved: onSaved, enabled: enabled, onReset: onReset, decoration: decoration, focusNode: focusNode, builder: (FormFieldState field) { final _SelectState state = field as _SelectState; // DropdownButtonFormField // TextFormField void changeValue(T? value) { state.didChange(value); } return InputDecorator( decoration: state.decoration().copyWith( floatingLabelBehavior: hint == null ? decoration.floatingLabelBehavior : FloatingLabelBehavior.always, filled: true, fillColor: CustomColor.bgGrayLight, ), isEmpty: state.value == null, child: Row( children: [ Expanded( child: DropdownButtonHideUnderline( child: DropdownButton( isExpanded: isExpanded, hint: hint, items: items, value: field.value, //field.value, style: style, isDense: isDense, disabledHint: field.value != null ? (items.firstWhereOrNull((val) => val.value == field.value)?.child ?? Text(field.value.toString())) : disabledHint, elevation: elevation, iconSize: iconSize, // icon: icon ?? svgImage(Images.icArrowDown, color: CustomColor.textGray, height: 8), iconDisabledColor: iconDisabledColor, iconEnabledColor: iconEnabledColor, onChanged: state.enabled ? (T? value) => changeValue(value) : null, onTap: onTap, focusNode: state.effectiveFocusNode, autofocus: autofocus, dropdownColor: dropdownColor, focusColor: focusColor, itemHeight: itemHeight, selectedItemBuilder: selectedItemBuilder, ), ), ), if (allowClear && state.enabled && field.value != null) ...[ ConstantWidget.widthSpace10, InkWell( onTap: () => changeValue(null), child: clearIcon, ), ] ], ), ); }, ); @override _SelectState createState() => _SelectState(); } class _SelectState extends FormBuilderFieldState, T> {}