Giter VIP home page Giter VIP logo

dropdown_button2's Introduction

Flutter DropdownButton2

Pub Version Flutter Version License: MIT Build Status

Intro

Flutter's core Dropdown Button widget with steady dropdown menu and many other options you can customize to your needs.

Image

Features

  • Dropdown menu always open below the button "as long as it's possible otherwise it'll open to the end of the screen" and you can edit its position by using the offset parameter.
  • You can control how (button, button's icon, dropdown menu and menu items) will be displayed "read Options below".
  • You can align (hint & value) and customize them.
  • You can edit the scrollbar's radius,thickness and isAlwaysShow.
  • You can set max height for the dropdown menu & it'll become scrollable if there are more items.
  • If you pass Null to dropdownMaxHeight parameter or didn't use it, the dropdown menu will take max height possible for the items and will become scrollable if there are more items.
  • If you have long scrollable list, the dropdown menu will auto scroll to current selected item and show it at the middle of the menu if possible.
  • Wrap DropdownButton2 with DropdownButtonHideUnderline to hide the underline.
  • A Custom widget of the DropdownButton2 below to make it more reusable. You can customize it to your needs and use it throughout all your app easily as shown in the examples.
  • You can use DropdownButton2 with items of different heights like dividers as shown in the examples.
  • You can use DropdownButton2 as Multiselect Dropdown with Checkboxes as shown in the examples.
  • You can use DropdownButton2 as Searchable Dropdown as shown in the examples.
  • You can use DropdownButton2 as a popup menu button by using the parameter customButton. You can pass Icon,Image or any widget and customize it as shown in the examples.
  • You can also use DropdownButtonFormField2 the same way with all options above and use it inside Form as shown in the examples.
  • Use decoration parameter for the DropdownButtonFormField2 to add borders, label and more.
  • You can customize DropdownButtonFormField2 width by wrapping it with Padding or with SizedBox and give it the width you want.

Options

DropdownButton2:

Option Description Type Required
items The list of items the user can select List<DropdownItem> Yes
selectedItemBuilder A builder to customize how the selected item will be displayed on the button DropdownButtonBuilder No
valueListenable A [ValueListenable] that represents the value of the currently selected [DropdownItem]. ValueListenable<T?>? No
multiValueListenable A [ValueListenable] that represents a list of the currently selected [DropdownItem]s ValueListenable<List<T>>? No
hint The placeholder displayed before the user choose an item Widget No
disabledHint The placeholder displayed if the dropdown is disabled Widget No
onChanged Called when the user selects an item ValueChanged<T?> No
onMenuStateChange Called when the dropdown menu opens or closes OnMenuStateChangeFn No
style The text style to use for text in the dropdown button and the dropdown menu TextStyle No
underline The widget to use for drawing the drop-down button's underline Widget No
isDense Reduce the button's height bool No
isExpanded Makes the button's inner contents expanded (set true to avoid long text overflowing) bool No
alignment Defines how the hint or the selected item is positioned within the button AlignmentGeometry No
buttonStyleData Used to configure the theme of the button ButtonStyleData No
iconStyleData Used to configure the theme of the button's icon IconStyleData No
dropdownStyleData Used to configure the theme of the dropdown menu DropdownStyleData No
menuItemStyleData Used to configure the theme of the dropdown menu items MenuItemStyleData No
dropdownSearchData Used to configure searchable dropdowns DropdownSearchData No
dropdownSeparator Adds separator widget to the dropdown menu DropdownSeparator No
customButton Uses custom widget like icon,image,etc.. instead of the default button Widget No
openWithLongPress Opens the dropdown menu on long-pressing instead of tapping bool No
barrierDismissible Whether you can dismiss this route by tapping the modal barrier bool No
barrierColor The color to use for the modal barrier. If this is null, the barrier will be transparent Color No
barrierLabel The semantic label used for a dismissible barrier String No
barrierCoversButton Specifies whether the modal barrier should cover the dropdown button or not. bool No
openDropdownListenable A [Listenable] that can be used to programmatically open the dropdown menu. Listenable? No

Subclass ButtonStyleData:

Option Description Type Required
height The height of the button double No
width The width of the button double No
padding The inner padding of the Button EdgeInsetsGeometry No
decoration The decoration of the Button BoxDecoration No
elevation The elevation of the Button int No
overlayColor Defines the ink response focus, hover, and splash colors for the button MaterialStateProperty<Color?> No

Subclass IconStyleData:

Option Description Type Required
icon The widget to use for the drop-down button's suffix icon Widget No
iconDisabledColor The color of the icon if the button is disabled Color No
iconEnabledColor The color of the icon if the button is enabled Color No
iconSize The size of the icon double No
openMenuIcon Shows different icon when dropdown menu is open Widget No

Subclass DropdownStyleData:

Option Description Type Required
maxHeight The maximum height of the dropdown menu double No
width The width of the dropdown menu double No
padding The inner padding of the dropdown menu EdgeInsetsGeometry No
scrollPadding The inner padding of the dropdown menu including the scrollbar EdgeInsetsGeometry No
decoration The decoration of the dropdown menu BoxDecoration No
elevation The elevation of the dropdown menu int No
direction The direction of the dropdown menu in relation to the button DropdownDirection No
offset Changes the position of the dropdown menu Offset No
isOverButton Opens the dropdown menu over the button instead of below it bool No
useSafeArea Determine if the dropdown menu should only display in safe areas of the screen bool No
useRootNavigator Determine whether to open the dropdown menu using the root Navigator or not bool No
scrollbarTheme Configures the theme of the menu's scrollbar ScrollbarThemeData No
openInterval The animation curve used for opening the dropdown menu (forward direction) Interval No
dropdownBuilder A builder to customize the dropdown menu DropdownBuilder No

Subclass MenuItemStyleData:

Option Description Type Required
padding The padding of menu items EdgeInsetsGeometry No
borderRadius The border radius of the menu item BorderRadius No
overlayColor Defines the ink response focus, hover, and splash colors for the items MaterialStateProperty<Color?> No
selectedMenuItemBuilder A builder to customize the selected menu item SelectedMenuItemBuilder No

Subclass DropdownSearchData:

Option Description Type Required
searchController The controller used for searchable dropdowns, if null, then it'll perform as a normal dropdown TextEditingController No
searchBarWidget The widget to be shown at the top of the dropdown menu for searchable dropdowns Widget No
searchBarWidgetHeight The height of the searchBarWidget if used double No
noResultsWidget The widget to show when the search results are empty Widget No
searchMatchFn The match function used for searchable dropdowns, if null, defaultFn will be used SearchMatchFn No

DropdownButtonFormField2 (In addition to the above):

Option Description Type Required
decoration The decoration of the dropdown button form field InputDecoration No
onSaved Called with the current selected item when the form is saved FormFieldSetter No
validator Called to validates if the input is invalid and display error text FormFieldValidator No
autovalidateMode Used to enable/disable auto validation AutovalidateMode No

Installation

add this line to pubspec.yaml

dependencies:
  dropdown_button2: ^3.0.0-beta.16

import package

import 'package:dropdown_button2/dropdown_button2.dart';

Usage and Examples

1. Simple DropdownButton2 with no styling:

Image

final List<String> items = [
  'Item1',
  'Item2',
  'Item3',
  'Item4',
];
final valueListenable = ValueNotifier<String?>(null);

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: DropdownButtonHideUnderline(
        child: DropdownButton2<String>(
          isExpanded: true,
          hint: Text(
            'Select Item',
            style: TextStyle(
              fontSize: 14,
              color: Theme.of(context).hintColor,
            ),
          ),
          items: items
              .map((String item) => DropdownItem<String>(
                    value: item,
                    height: 40,
                    child: Text(
                      item,
                      style: const TextStyle(
                        fontSize: 14,
                      ),
                    ),
                  ))
              .toList(),
          valueListenable: valueListenable,
          onChanged: (String? value) {
            valueListenable.value = value;
          },
          buttonStyleData: const ButtonStyleData(
            padding: EdgeInsets.symmetric(horizontal: 16),
            height: 40,
            width: 140,
          ),
        ),
      ),
    ),
  );
}

2. DropdownButton2 with few styling and customization:

Image

final List<String> items = [
  'Item1',
  'Item2',
  'Item3',
  'Item4',
  'Item5',
  'Item6',
  'Item7',
  'Item8',
];
final valueListenable = ValueNotifier<String?>(null);

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: DropdownButtonHideUnderline(
        child: DropdownButton2<String>(
          isExpanded: true,
          hint: const Row(
            children: [
              Icon(
                Icons.list,
                size: 16,
                color: Colors.yellow,
              ),
              SizedBox(
                width: 4,
              ),
              Expanded(
                child: Text(
                  'Select Item',
                  style: TextStyle(
                    fontSize: 14,
                    fontWeight: FontWeight.bold,
                    color: Colors.yellow,
                  ),
                  overflow: TextOverflow.ellipsis,
                ),
              ),
            ],
          ),
          items: items
              .map((String item) => DropdownItem<String>(
                    value: item,
                    height: 40,
                    child: Text(
                      item,
                      style: const TextStyle(
                        fontSize: 14,
                        fontWeight: FontWeight.bold,
                        color: Colors.white,
                      ),
                      overflow: TextOverflow.ellipsis,
                    ),
                  ))
              .toList(),
          valueListenable: valueListenable,
          onChanged: (value) {
            valueListenable.value = value;
          },
          buttonStyleData: ButtonStyleData(
            height: 50,
            width: 160,
            padding: const EdgeInsets.only(left: 14, right: 14),
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(14),
              border: Border.all(
                color: Colors.black26,
              ),
              color: Colors.redAccent,
            ),
            elevation: 2,
          ),
          iconStyleData: const IconStyleData(
            icon: Icon(
              Icons.arrow_forward_ios_outlined,
            ),
            iconSize: 14,
            iconEnabledColor: Colors.yellow,
            iconDisabledColor: Colors.grey,
          ),
          dropdownStyleData: DropdownStyleData(
            maxHeight: 200,
            width: 200,
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(14),
              color: Colors.redAccent,
            ),
            offset: const Offset(-20, 0),
            scrollbarTheme: ScrollbarThemeData(
              radius: const Radius.circular(40),
              thickness: MaterialStateProperty.all(6),
              thumbVisibility: MaterialStateProperty.all(true),
            ),
          ),
          menuItemStyleData: const MenuItemStyleData(
            padding: EdgeInsets.only(left: 14, right: 14),
          ),
        ),
      ),
    ),
  );
}

3. DropdownButton2 with separator widgets like dividers:

Image

final List<String> items = [
  'Item1',
  'Item2',
  'Item3',
  'Item4',
];
final valueListenable = ValueNotifier<String?>(null);

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: DropdownButtonHideUnderline(
        child: DropdownButton2<String>(
          isExpanded: true,
          hint: Text(
            'Select Item',
            style: TextStyle(
              fontSize: 14,
              color: Theme.of(context).hintColor,
            ),
          ),
          items: items
              .map((String item) => DropdownItem<String>(
                    value: item,
                    height: 40,
                    child: Padding(
                      padding: const EdgeInsets.symmetric(horizontal: 8.0),
                      child: Text(
                        item,
                        style: const TextStyle(
                          fontSize: 14,
                        ),
                      ),
                    ),
                  ))
              .toList(),
          dropdownSeparator: const DropdownSeparator(
            height: 4,
            child: Padding(
              padding: EdgeInsets.symmetric(horizontal: 8.0),
              child: Divider(),
            ),
          ),
          valueListenable: valueListenable,
          onChanged: (value) {
            valueListenable.value = value;
          },
          buttonStyleData: const ButtonStyleData(
            padding: EdgeInsets.symmetric(horizontal: 16),
            height: 40,
            width: 140,
          ),
          dropdownStyleData: const DropdownStyleData(
            maxHeight: 200,
          ),
          menuItemStyleData: const MenuItemStyleData(
            padding: EdgeInsets.symmetric(horizontal: 8.0),
          ),
          iconStyleData: const IconStyleData(
            openMenuIcon: Icon(Icons.arrow_drop_up),
          ),
        ),
      ),
    ),
  );
}

4. DropdownButton2 as Multiselect Dropdown with Checkboxes:

Image

final List<String> items = [
  'All',
  'Item1',
  'Item2',
  'Item3',
  'Item4',
];
final multiValueListenable = ValueNotifier<List<String>>([]);

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: DropdownButtonHideUnderline(
        child: DropdownButton2<String>(
          isExpanded: true,
          hint: Text(
            'Select Items',
            style: TextStyle(
              fontSize: 14,
              color: Theme.of(context).hintColor,
            ),
          ),
          items: items.map((item) {
            return DropdownItem(
              value: item,
              height: 40,
              closeOnTap: false,
              child: ValueListenableBuilder<List<String>>(
                valueListenable: multiValueListenable,
                builder: (context, multiValue, _) {
                  final isSelected = multiValue.contains(item);
                  return Container(
                    height: double.infinity,
                    padding: const EdgeInsets.symmetric(horizontal: 16.0),
                    child: Row(
                      children: [
                        if (isSelected)
                          const Icon(Icons.check_box_outlined)
                        else
                          const Icon(Icons.check_box_outline_blank),
                        const SizedBox(width: 16),
                        Expanded(
                          child: Text(
                            item,
                            style: const TextStyle(
                              fontSize: 14,
                            ),
                          ),
                        ),
                      ],
                    ),
                  );
                },
              ),
            );
          }).toList(),
          multiValueListenable: multiValueListenable,
          onChanged: (value) {
            final multiValue = multiValueListenable.value;
            final isSelected = multiValue.contains(value);
            if (value == 'All') {
              isSelected
                  ? multiValueListenable.value = []
                  : multiValueListenable.value = List.from(items);
            } else {
              multiValueListenable.value = isSelected
                  ? ([...multiValue]..remove(value))
                  : [...multiValue, value!];
            }
          },
          selectedItemBuilder: (context) {
            return items.map(
              (item) {
                return ValueListenableBuilder<List<String>>(
                    valueListenable: multiValueListenable,
                    builder: (context, multiValue, _) {
                      return Container(
                        alignment: AlignmentDirectional.center,
                        child: Text(
                          multiValue
                              .where((item) => item != 'All')
                              .join(', '),
                          style: const TextStyle(
                            fontSize: 14,
                            overflow: TextOverflow.ellipsis,
                          ),
                          maxLines: 1,
                        ),
                      );
                    });
              },
            ).toList();
          },
          buttonStyleData: const ButtonStyleData(
            padding: EdgeInsets.only(left: 16, right: 8),
            height: 40,
            width: 140,
          ),
          menuItemStyleData: const MenuItemStyleData(
            padding: EdgeInsets.zero,
          ),
        ),
      ),
    ),
  );
}

5. DropdownButton2 as Searchable Dropdown:

Image

final List<String> items = [
  'A_Item1',
  'A_Item2',
  'A_Item3',
  'A_Item4',
  'B_Item1',
  'B_Item2',
  'B_Item3',
  'B_Item4',
];

final valueListenable = ValueNotifier<String?>(null);
final TextEditingController textEditingController = TextEditingController();

@override
void dispose() {
  textEditingController.dispose();
  super.dispose();
}

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: DropdownButtonHideUnderline(
        child: DropdownButton2<String>(
          isExpanded: true,
          hint: Text(
            'Select Item',
            style: TextStyle(
              fontSize: 14,
              color: Theme.of(context).hintColor,
            ),
          ),
          items: items
              .map((item) => DropdownItem(
                    value: item,
                    height: 40,
                    child: Text(
                      item,
                      style: const TextStyle(
                        fontSize: 14,
                      ),
                    ),
                  ))
              .toList(),
          valueListenable: valueListenable,
          onChanged: (value) {
            valueListenable.value = value;
          },
          buttonStyleData: const ButtonStyleData(
            padding: EdgeInsets.symmetric(horizontal: 16),
            height: 40,
            width: 200,
          ),
          dropdownStyleData: const DropdownStyleData(
            maxHeight: 200,
          ),
          dropdownSearchData: DropdownSearchData(
            searchController: textEditingController,
            searchBarWidgetHeight: 50,
            searchBarWidget: Container(
              height: 50,
              padding: const EdgeInsets.only(
                top: 8,
                bottom: 4,
                right: 8,
                left: 8,
              ),
              child: TextFormField(
                expands: true,
                maxLines: null,
                controller: textEditingController,
                decoration: InputDecoration(
                  isDense: true,
                  contentPadding: const EdgeInsets.symmetric(
                    horizontal: 10,
                    vertical: 8,
                  ),
                  hintText: 'Search for an item...',
                  hintStyle: const TextStyle(fontSize: 12),
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(8),
                  ),
                ),
              ),
            ),
            noResultsWidget: const Padding(
              padding: EdgeInsets.all(8),
              child: Text('No Item Found!'),
            ),
            searchMatchFn: (item, searchValue) {
              return item.value.toString().contains(searchValue);
            },
          ),
          //This to clear the search value when you close the menu
          onMenuStateChange: (isOpen) {
            if (!isOpen) {
              textEditingController.clear();
            }
          },
        ),
      ),
    ),
  );
}

6. DropdownButton2 as Popup menu button using customButton parameter:

Example 1 using icon:

Image

class PopupIconExample extends StatefulWidget {
  const PopupIconExample({super.key});

  @override
  State<PopupIconExample> createState() => _PopupIconExampleState();
}

class _PopupIconExampleState extends State<PopupIconExample> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: DropdownButtonHideUnderline(
          child: DropdownButton2(
            customButton: const Icon(
              Icons.list,
              size: 46,
              color: Colors.red,
            ),
            items: [
              ..._MenuItems.firstItems.map(
                (item) => DropdownItem<_MenuItem>(
                  value: item,
                  height: 48,
                  child: _MenuItems.buildItem(item),
                ),
              ),
              const DropdownItem<Divider>(
                enabled: false,
                height: 8,
                child: Divider(),
              ),
              ..._MenuItems.secondItems.map(
                (item) => DropdownItem<_MenuItem>(
                  value: item,
                  height: 48,
                  child: _MenuItems.buildItem(item),
                ),
              ),
            ],
            onChanged: (value) {
              _MenuItems.onChanged(context, value! as _MenuItem);
            },
            dropdownStyleData: DropdownStyleData(
              width: 160,
              padding: const EdgeInsets.symmetric(vertical: 6),
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(4),
                color: Colors.redAccent,
              ),
              offset: const Offset(0, 8),
            ),
            menuItemStyleData: const MenuItemStyleData(
              padding: EdgeInsets.only(left: 16, right: 16),
            ),
          ),
        ),
      ),
    );
  }
}

class _MenuItem {
  const _MenuItem({
    required this.text,
    required this.icon,
  });

  final String text;
  final IconData icon;
}

abstract class _MenuItems {
  static const List<_MenuItem> firstItems = [home, share, settings];
  static const List<_MenuItem> secondItems = [logout];

  static const home = _MenuItem(text: 'Home', icon: Icons.home);
  static const share = _MenuItem(text: 'Share', icon: Icons.share);
  static const settings = _MenuItem(text: 'Settings', icon: Icons.settings);
  static const logout = _MenuItem(text: 'Log Out', icon: Icons.logout);

  static Widget buildItem(_MenuItem item) {
    return Row(
      children: [
        Icon(item.icon, color: Colors.white, size: 22),
        const SizedBox(
          width: 10,
        ),
        Expanded(
          child: Text(
            item.text,
            style: const TextStyle(
              color: Colors.white,
            ),
          ),
        ),
      ],
    );
  }

  static void onChanged(BuildContext context, _MenuItem item) {
    switch (item) {
      case _MenuItems.home:
        //Do something
        break;
      case _MenuItems.settings:
        //Do something
        break;
      case _MenuItems.share:
        //Do something
        break;
      case _MenuItems.logout:
        //Do something
        break;
    }
  }
}

Example 2 using image and openWithLongPress parameter:

Image

class PopupImageExample extends StatefulWidget {
  const PopupImageExample({super.key});

  @override
  State<PopupImageExample> createState() => _PopupImageExampleState();
}

class _PopupImageExampleState extends State<PopupImageExample> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: DropdownButtonHideUnderline(
          child: DropdownButton2(
            customButton: Container(
              height: 240,
              width: 240,
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(40),
                image: const DecorationImage(
                  image: AssetImage(
                    'assets/images/city.jpg',
                  ),
                  fit: BoxFit.cover,
                ),
              ),
            ),
            openWithLongPress: true,
            items: [
              ..._MenuItems.firstItems.map(
                (item) => DropdownItem<_MenuItem>(
                  value: item,
                  height: 48,
                  child: _MenuItems.buildItem(item),
                ),
              ),
              const DropdownItem<Divider>(
                enabled: false,
                height: 8,
                child: Divider(),
              ),
              ..._MenuItems.secondItems.map(
                (item) => DropdownItem<_MenuItem>(
                  value: item,
                  height: 48,
                  child: _MenuItems.buildItem(item),
                ),
              ),
            ],
            onChanged: (value) {
              _MenuItems.onChanged(context, value! as _MenuItem);
            },
            buttonStyleData: ButtonStyleData(
              // This is necessary for the ink response to match our customButton radius.
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(40),
              ),
            ),
            dropdownStyleData: DropdownStyleData(
              width: 160,
              padding: const EdgeInsets.symmetric(vertical: 6),
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(4),
                color: Colors.redAccent,
              ),
              offset: const Offset(40, -4),
            ),
            menuItemStyleData: const MenuItemStyleData(
              padding: EdgeInsets.only(left: 16, right: 16),
            ),
          ),
        ),
      ),
    );
  }
}

class _MenuItem {
  const _MenuItem({
    required this.text,
    required this.icon,
  });

  final String text;
  final IconData icon;
}

class _MenuItems {
  static const List<_MenuItem> firstItems = [like, share, download];
  static const List<_MenuItem> secondItems = [cancel];

  static const like = _MenuItem(text: 'Like', icon: Icons.favorite);
  static const share = _MenuItem(text: 'Share', icon: Icons.share);
  static const download = _MenuItem(text: 'Download', icon: Icons.download);
  static const cancel = _MenuItem(text: 'Cancel', icon: Icons.cancel);

  static Widget buildItem(_MenuItem item) {
    return Row(
      children: [
        Icon(
          item.icon,
          color: Colors.white,
          size: 22,
        ),
        const SizedBox(
          width: 10,
        ),
        Expanded(
          child: Text(
            item.text,
            style: const TextStyle(
              color: Colors.white,
            ),
          ),
        ),
      ],
    );
  }

  static void onChanged(BuildContext context, _MenuItem item) {
    switch (item) {
      case _MenuItems.like:
        //Do something
        break;
      case _MenuItems.share:
        //Do something
        break;
      case _MenuItems.download:
        //Do something
        break;
      case _MenuItems.cancel:
        //Do something
        break;
    }
  }
}

7. Using DropdownButtonFormField2 with Form:

Image

final List<String> genderItems = [
  'Male',
  'Female',
];
final valueListenable = ValueNotifier<String?>(null);

final _formKey = GlobalKey<FormState>();

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Form(
      key: _formKey,
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 80),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TextFormField(
              decoration: InputDecoration(
                contentPadding: const EdgeInsets.all(16),
                hintText: 'Enter Your Full Name.',
                hintStyle: const TextStyle(fontSize: 14),
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(15),
                ),
              ),
            ),
            const SizedBox(height: 30),
            DropdownButtonFormField2<String>(
              isExpanded: true,
              decoration: InputDecoration(
                // Add Horizontal padding using menuItemStyleData.padding so it matches
                // the menu padding when button's width is not specified.
                contentPadding: const EdgeInsets.symmetric(vertical: 16),
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(15),
                ),
                // Add more decoration..
              ),
              hint: const Text(
                'Select Your Gender',
                style: TextStyle(fontSize: 14),
              ),
              items: genderItems
                  .map((item) => DropdownItem<String>(
                        value: item,
                        child: Text(
                          item,
                          style: const TextStyle(
                            fontSize: 14,
                          ),
                        ),
                      ))
                  .toList(),
              valueListenable: valueListenable,
              validator: (value) {
                if (value == null) {
                  return 'Please select gender.';
                }
                return null;
              },
              onChanged: (value) {
                valueListenable.value = value;
              },
              iconStyleData: const IconStyleData(
                icon: Icon(
                  Icons.arrow_drop_down,
                  color: Colors.black45,
                ),
              ),
              dropdownStyleData: DropdownStyleData(
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(15),
                ),
              ),
              menuItemStyleData: const MenuItemStyleData(
                padding: EdgeInsets.symmetric(horizontal: 16),
              ),
            ),
            const SizedBox(height: 30),
            TextButton(
              onPressed: () {
                if (_formKey.currentState!.validate()) {
                  // Do something.
                }
              },
              child: const Text('Submit Button'),
            ),
          ],
        ),
      ),
    ),
  );
}

How to make a reusable DropdownButton2 for your app

class CustomDropdownButton2 extends StatelessWidget {
  const CustomDropdownButton2({
    required this.hint,
    required this.valueListenable,
    required this.dropdownItems,
    required this.onChanged,
    this.selectedItemBuilder,
    this.hintAlignment,
    this.valueAlignment,
    this.buttonHeight,
    this.buttonWidth,
    this.buttonPadding,
    this.buttonDecoration,
    this.buttonElevation,
    this.icon,
    this.iconSize,
    this.iconEnabledColor,
    this.iconDisabledColor,
    this.itemHeight,
    this.itemPadding,
    this.dropdownHeight,
    this.dropdownWidth,
    this.dropdownPadding,
    this.dropdownDecoration,
    this.dropdownElevation,
    this.scrollbarRadius,
    this.scrollbarThickness,
    this.scrollbarAlwaysShow,
    this.offset = Offset.zero,
    super.key,
  });
  final String hint;
  final ValueListenable<String?>? valueListenable;
  final List<String> dropdownItems;
  final ValueChanged<String?>? onChanged;
  final DropdownButtonBuilder? selectedItemBuilder;
  final Alignment? hintAlignment;
  final Alignment? valueAlignment;
  final double? buttonHeight, buttonWidth;
  final EdgeInsetsGeometry? buttonPadding;
  final BoxDecoration? buttonDecoration;
  final int? buttonElevation;
  final Widget? icon;
  final double? iconSize;
  final Color? iconEnabledColor;
  final Color? iconDisabledColor;
  final double? itemHeight;
  final EdgeInsetsGeometry? itemPadding;
  final double? dropdownHeight, dropdownWidth;
  final EdgeInsetsGeometry? dropdownPadding;
  final BoxDecoration? dropdownDecoration;
  final int? dropdownElevation;
  final Radius? scrollbarRadius;
  final double? scrollbarThickness;
  final bool? scrollbarAlwaysShow;
  final Offset offset;

  @override
  Widget build(BuildContext context) {
    return DropdownButtonHideUnderline(
      child: DropdownButton2<String>(
        //To avoid long text overflowing.
        isExpanded: true,
        hint: Container(
          alignment: hintAlignment,
          child: Text(
            hint,
            overflow: TextOverflow.ellipsis,
            maxLines: 1,
            style: TextStyle(
              fontSize: 14,
              color: Theme.of(context).hintColor,
            ),
          ),
        ),
        valueListenable: valueListenable,
        items: dropdownItems
            .map((String item) => DropdownItem<String>(
                  value: item,
                  height: itemHeight ?? 40,
                  child: Container(
                    alignment: valueAlignment,
                    child: Text(
                      item,
                      overflow: TextOverflow.ellipsis,
                      maxLines: 1,
                      style: const TextStyle(
                        fontSize: 14,
                      ),
                    ),
                  ),
                ))
            .toList(),
        onChanged: onChanged,
        selectedItemBuilder: selectedItemBuilder,
        buttonStyleData: ButtonStyleData(
          height: buttonHeight ?? 40,
          width: buttonWidth ?? 140,
          padding: buttonPadding ?? const EdgeInsets.only(left: 14, right: 14),
          decoration: buttonDecoration ??
              BoxDecoration(
                borderRadius: BorderRadius.circular(14),
                border: Border.all(
                  color: Colors.black45,
                ),
              ),
          elevation: buttonElevation,
        ),
        iconStyleData: IconStyleData(
          icon: icon ?? const Icon(Icons.arrow_forward_ios_outlined),
          iconSize: iconSize ?? 12,
          iconEnabledColor: iconEnabledColor,
          iconDisabledColor: iconDisabledColor,
        ),
        dropdownStyleData: DropdownStyleData(
          //Max height for the dropdown menu & becoming scrollable if there are more items. If you pass Null it will take max height possible for the items.
          maxHeight: dropdownHeight ?? 200,
          width: dropdownWidth ?? 140,
          padding: dropdownPadding,
          decoration: dropdownDecoration ??
              BoxDecoration(
                borderRadius: BorderRadius.circular(14),
              ),
          elevation: dropdownElevation ?? 8,
          //Null or Offset(0, 0) will open just under the button. You can edit as you want.
          offset: offset,
          scrollbarTheme: ScrollbarThemeData(
            radius: scrollbarRadius ?? const Radius.circular(40),
            thickness: scrollbarThickness != null
                ? MaterialStateProperty.all<double>(scrollbarThickness!)
                : null,
            thumbVisibility: scrollbarAlwaysShow != null
                ? MaterialStateProperty.all<bool>(scrollbarAlwaysShow!)
                : null,
          ),
        ),
        menuItemStyleData: MenuItemStyleData(
          padding: itemPadding ?? const EdgeInsets.only(left: 14, right: 14),
        ),
      ),
    );
  }
}

Thanks

If something is missing or you want to add some feature, feel free to open a ticket or contribute!

LICENSE: MIT

dropdown_button2's People

Contributors

ahmedlsayed9 avatar apdos avatar carleondev avatar chayanforyou avatar dependabot[bot] avatar hlvs-apps avatar maximilianflechtner avatar maxstubbersfield avatar pawlowskim avatar selsapingardi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

dropdown_button2's Issues

The dropdown menu is blocked by the tabbar

When my dropdown button is very close to the tabar,
The menu will be covered by the tabbar and cannot be displayed.
Use dropdown on a scrollable form, which happens when the dropdown scrolls to the bottom

Center label text with icon

Hello,

I've recently started work on a new mobile app and I am using the dropdown_button2 widget. For the most part it works great, better than the widget provided by Flutter, but there's one issue that's annoying me a bit.

I'm trying to center the label text (the selected value) but the problem is when I use an Icon whilst trying to center the text, the alignment.center takes into account the icon when centering which results into the following.

flutter app

Technicaly it has centered both elements, but I want the icon to be on the far right whilst having the text be centered with the cog icon just above. I'm not sure if this is somehow possible, but I've tried for a couple of hours now to try and center it but it doesn't seem to be possible at the moment.

I've tried adding some padding so that the text is centered but what happens then is the list of elements has more spacing on the left than on the right.

flutter app 2.

And I've also tried removing the icon from the widget and putting it inside a row with dropdown_button2 but what happens then is when I click on the icon, it doesn't open the dropdown menu.

Thanks in advance for the help.

Disable Attribute

Hello,
Is there any way to make this input a disabled field?

Thanks

Not run when apply CustomDropdownButton2 when run on web

======== Exception caught by widgets library =======================================================
The following assertion was thrown building DropdownButton2(dirty, state: _DropdownButton2State#5ac76):
No Material widget found.

DropdownButton2 widgets require a Material widget ancestor.
In material design, most widgets are conceptually "printed" on a sheet of material. In Flutter's material library, that material is represented by the Material widget. It is the Material widget that renders ink splashes, for instance. Because of this, many material library widgets require that there be a Material widget in the tree above them.

To introduce a Material widget, you can either directly include one, or use a widget that contains Material itself, such as a Card, Dialog, Drawer, or Scaffold.

Label after selection

What I really need is a label after drop down choice selection (like textFormField has)

So reference 'First Name' in the screen shot

Screen Shot 2022-02-11 at 8 28 29 AM

So I'm putting in a feature request here...

Issue with margin of dropdown

I have started using with my design all going well but when I started giving margins to dropdown it's sets well but when I see the listed items doesn't get the outer margin they always stick to the start not aligned with the main box
4d046722-1190-4387-903f-c8e3c43df4ae

fontSize don't work

Hi.
How to change fontSize of Text inner Button.
I tried.

          DropdownButton2(
                    onChanged: (text) {},
                    underline: const SizedBox.shrink(),
                    dropdownDecoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(14),
                    ),
                    value: state.dot.first.tenDot,
                    alignment: Alignment.center,
                    buttonDecoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(14),
                      border: Border.all(color: Colors.black26,),
                    ),
                    style: const TextStyle(
                      color: Colors.black,
                      fontSize: 10
                    ),
        )

But It's don't work.

CustomButton has a Delete line

Hi, This is a good library, but I have a problem. I set a CustomButton but it has a delete line. I can't remove it. This is my code

DropdownButton2<T>(
      isExpanded: true,
      customButton: Row(mainAxisSize: MainAxisSize.max, children: <Widget>[hint, SvgPicture.asset(getPic('icon_menu_down.svg'), width: 7, height: 7)]),
      items: items,
      value: selectValue,
      onChanged: onChanged,
      icon: SvgPicture.asset(
        getPic('icon_menu_down.svg'),
        width: 7,
        height: 7,
      ),
      buttonHeight: 20,
      buttonWidth: 140,
      itemHeight: 40,
      itemPadding: const EdgeInsets.symmetric(horizontal: 12),
      dropdownMaxHeight: 200,
      dropdownWidth: 200,
      dropdownDecoration: ViewDecoration.decoration(),
      // dropdownElevation: 4,
      scrollbarRadius: const Radius.circular(40),
      scrollbarThickness: 4,
      scrollbarAlwaysShow: true,
      offset: const Offset(-20, -10),
    )

image

dropdown_button2 and divider

hello. I use your dropdown_button2 v.1.0.7 library, it is very cool and convenient. Thanks to it, very convenient and beautiful menus are obtained. But I noticed such a nuance, I need to make the dividers in the menu equal to the width of the menu, and the edges of the menu rounded. These are the conditions of the application design. If I do this, then when scrolling through the menu, the list separators go beyond the menu boundaries. Can this be fixed? Thanks.

Cupertino?

Hi, is this component relying on the MaterialApp or can you use it in CupertinoApp as well?

issue with the new search feature

First of all, I'd like to thank you for implementing the new search feature.

There is one little issue, it won't work if the unique value is not the string inside the dropdown (id instead of name).

which means I need to refilter again to get the name. It works but it is slow.

Besides I need to return the whole object after selection which means I need to refilter again.

Code_pjwKfMvLoz

There is also a small visual issue, when the selected item is scrolled:

gdm_bloc_AxV2ZsQjPu.mp4

Accessing _isMenuOpen

Goal:
I need to pass the _isMenuOpen attribute to my custom customButton.

Solution i found:
I use onTap/onMenuClose to set a state in my CustomDropdown widget (statefull), and i pass it to my customButton.

Sugestion:
Is there a better way to achieve this?
If not, is it possible to be acomplished with a single callback, that receives the actual _isMenuOpen value so i can ensure that my state and dropdown_button2 state are the same?

MyDropdown extends from stateful ....
isOpen = false;

`DropdownButtonFormField2(

isOpen: (value){
  setState((){
    isOpen = value;
  });
},
)

or

Changing the customButton from expecting a Widget to expecting a function that return a Widget and returns the _isMenuOpen as a parameter:
customButton: (isOpen) => MyWidget(isOpen),

Clip behavior for dropDown

If we have rounded corners on dropDown, scrollbar is partically outside of dropDown. Usually we have "clipBehavior" on widgets to control it. Are we have something to fix it for DropdownButtonFormField2?

Screenshot_20220406-145741__01

Dropdown Menu overlays BottomNavigationBar

Hello,

I'm using dropdown_button2: ^1.5.2. My dropdown menu is overlaying my BottomNavigationBar like this:
DropdownButton2

In comparison the standard behaviour of default flutter DropdownButton:
DropdownButton

I'm using DropdownButtonFormField2 inside a widget tree like this:

Scaffold
  SingleChildScrollView
    Column
      Padding
        DropdownButtonFormField2
Padding(
	padding: const EdgeInsets.fromLTRB(40, 20, 40, 20),
	child: DropdownButtonFormField2(
	  decoration: InputDecoration(
	    //Add isDense true and zero Padding.
	    //Add Horizontal padding using buttonPadding and Vertical padding by increasing buttonHeight instead of add Padding here so that The whole TextField Button become clickable, and also the dropdown menu open under The whole TextField Button.
	    isDense: true,
	    contentPadding: EdgeInsets.zero,
	    border: OutlineInputBorder(
	      borderRadius: BorderRadius.circular(15),
	    ),
	    //Add more decoration as you want here
	    //Add label If you want but add hint outside the decoration to be aligned in the button perfectly.
	  ),
	  isExpanded: true,
	  value: selectedCountry,
	  icon: Icon(
	    Icons.arrow_drop_down,
	    color: Colors.white,
	  ),
	  iconSize: 30,
	  buttonHeight: 48,
	  buttonPadding:
	      const EdgeInsets.only(left: 20, right: 10),
	  dropdownDecoration: BoxDecoration(
	    borderRadius: BorderRadius.circular(15),
	  ),
	  items: countries.map((CountryItem country) {
	    return DropdownMenuItem<CountryItem>(
	      value: country,
	      child: Row(
		crossAxisAlignment: CrossAxisAlignment.center,
		children: <Widget>[
		  Image.asset(
		    "assets/images/flags/" +
		        country.code +
		        ".png",
		    height: 20,
		    width: 25,
		  ),
		  SizedBox(
		    width: 10,
		  ),
		  Text(country.name),
		],
	      ),
	    );
	  }).toList(),
	  onChanged: (CountryItem? country) {
	    setState(() {
	      selectedCountry = country;
	    });
	  },
	  onSaved: (value) {},
	),
),

dropdownOverButton, dropdownFullScreen and offset aren't working either. Any ideas?

flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel master, 3.1.0-0.0.pre.939, on Fedora Linux 36 (Workstation Edition) 5.17.8-300.fc36.x86_64, locale de_DE.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 32.1.0-rc1)
[✗] Chrome - develop for the web (Cannot find Chrome executable at google-chrome)
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.
[✗] Linux toolchain - develop for Linux desktop
    ✗ clang++ is required for Linux development.
      It is likely available from your distribution (e.g.: apt install clang), or can be downloaded from https://releases.llvm.org/
    ✗ CMake is required for Linux development.
      It is likely available from your distribution (e.g.: apt install cmake), or can be downloaded from https://cmake.org/download/
    ✗ ninja is required for Linux development.
      It is likely available from your distribution (e.g.: apt install ninja-build), or can be downloaded from
      https://github.com/ninja-build/ninja/releases
    ✗ GTK 3.0 development libraries are required for Linux development.
      They are likely available from your distribution (e.g.: apt install libgtk-3-dev)
[✓] Android Studio (version 2021.1)
[✓] VS Code (version 1.67.2)
[✓] Connected device (2 available)
[✓] HTTP Host Availability

! Doctor found issues in 2 categories.

Label is not aligned to start of field

Hi, and thanks for this awesome package!

There's an issue with the label text, where it should appear at the beginning of the field, but it's significantly offset from the left side in my case. Notice in the screenshot how the dropdown buttons' labels are closer to the start of the field, but the DropdownButtonFormField2's label is offset:

Screen Shot 2022-04-22 at 6 40 44 PM
.

How to avoid rebuilding of whole widget tree

I'm using dropdown button inside of futureBuilder, but when I try to select some option whole widget tree rebuilds. How to avoid rebuilding of whole widget tree.

Center(
          child: FutureBuilder(
            future: employee,
            builder: ((context, AsyncSnapshot snapshot) {
              switch(snapshot.connectionState) {
                case ConnectionState.done:
                  return SingleChildScrollView(
                    child: Container(
                      width: 300,
                      height: 650,
                      decoration: BoxDecoration(
                          border: Border.all(color: Theme.of(context).primaryColor),
                          borderRadius: BorderRadius.circular(16)),
                      padding: const EdgeInsets.all(16),
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.start,
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          const Text(
                            'Редактирование данных сотрудника',
                            style: TextStyle(fontWeight: FontWeight.bold),
                          ),
                          const Divider(),
                          TextFormField(
                            controller: username,
                            decoration: const InputDecoration(
                              border: UnderlineInputBorder(),
                              labelText: 'Логин',
                            ),
                          ),
                          const SizedBox(
                            height: 30,
                          ),
                          TextFormField(
                            controller: password,
                            obscureText: true,
                            decoration: const InputDecoration(
                              border: UnderlineInputBorder(),
                              labelText: 'Пароль',
                            ),
                          ),
                          const SizedBox(
                            height: 30,
                          ),
                          TextFormField(
                            controller: confirmPassword,
                            obscureText: true,
                            decoration: const InputDecoration(
                              border: UnderlineInputBorder(),
                              labelText: 'Подтвердите пароль',
                            ),
                          ),
                          const SizedBox(
                            height: 30,
                          ),
                          TextFormField(
                            controller: firstname,
                            decoration: const InputDecoration(
                              border: UnderlineInputBorder(),
                              labelText: 'Имя сотрудника',
                            ),
                          ),
                          const SizedBox(
                            height: 30,
                          ),
                          TextFormField(
                            controller: lastname,
                            decoration: const InputDecoration(
                              border: UnderlineInputBorder(),
                              labelText: 'Фамилия сотрудника',
                            ),
                          ),
                          const SizedBox(
                            height: 30,
                          ),
                          const Text('Роль сотрудника'),
                          DropdownButton2(
                            isExpanded: true,
                            dropdownWidth: 300,
                            buttonPadding: const EdgeInsets.symmetric(horizontal: 16),
                            barrierColor: Colors.grey.withOpacity(0.2),
                            hint: Text(
                              'Выберите роль сотрудника',
                              style: TextStyle(
                                fontSize: 14,
                                color: Theme.of(context).hintColor,
                              ),
                            ),
                            items: userTypes
                                .map((item) => DropdownMenuItem<String>(
                                      value: item,
                                      child: Text(
                                        item,
                                        style: const TextStyle(
                                          fontSize: 14,
                                        ),
                                      ),
                                    ))
                                .toList(),
                            value: selectedType,
                            onChanged: (value) {
                              setState(() {
                                selectedType = value as String;
                              });
                            },
                            buttonHeight: 40,
                            buttonWidth: 300,
                            itemHeight: 40,
                          ),
                          const SizedBox(height: 30),
                          ElevatedButton(
                              onPressed: () {
                                updateEmployee(employeeId);
                              },
                              child: const Text('Редактировать'))
                        ],
                      ),
                    ),
                  );
                case ConnectionState.active:
                  return const CircularProgressIndicator();
                case ConnectionState.none:
                  return const CircularProgressIndicator();
                case ConnectionState.waiting: 
                  return const CircularProgressIndicator();
              }
            }),
          ),
    )

searchbar for a long list with objects instead of string

This is by far the best dropdown menu in pub.dev.

  • adding list of Objects instead of list of strings and adding a required label (ex Object.name)

  • i have a lot of duplicate names, using only strings is not an option

  • Adding an optional searchBar to filter items in a long list would make it perfect

Closing this issue due to lack of information. Feel free to reopen with more details if you still have trouble.

Closing this issue due to lack of information. Feel free to reopen with more details if you still have trouble.

Originally posted by @AhmedLSayed9 in #25 (comment)

f108e606d833fd6a8855d3283ce7375b.mp4
  String? selectedValue;
  List<String> items = [
    'Item1',
    'Item2',
    'Item3',
    'Item4',
  ];

  StickyPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size;
    final width = size.width;

    return Scaffold(
      appBar: AppBar(title: Text("select demo")),
      body: Stack(
        children: [
          CustomScrollView(
            slivers: <Widget>[
              _selectMean(context, width),
            ],
          ),
        ],
      ),
    );
  }

  Widget _selectMean(context, width) {
    return SliverToBoxAdapter(
      child: DropdownButtonHideUnderline(
        child: DropdownButtonFormField2(
          onTap: () {},
          offset: const Offset(10, 50),
          alignment: AlignmentDirectional.centerStart,
          // selectedItemHighlightColor: Colors.blue,
          dropdownWidth: width - 20.w,
          decoration: InputDecoration(
            isDense: true,
            contentPadding: EdgeInsets.zero,
            border: OutlineInputBorder(
              borderRadius: BorderRadius.circular(15),
            ),
          ),
          hint: const Text(
            'Choose Text',
            style: TextStyle(fontSize: 14, color: Colors.blue),
          ),
          icon: const Icon(
            Icons.arrow_drop_down,
            color: Colors.black45,
          ),
          iconSize: 30,
          buttonHeight: 60,
          buttonPadding: const EdgeInsets.only(left: 20, right: 10),
          dropdownDecoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.circular(15),
            boxShadow: const [],
          ),
          items: items
              .map((item) => DropdownMenuItem<String>(
                    value: item,
                    child: Text(
                      item,
                      style: const TextStyle(fontSize: 14, color: Colors.red),
                    ),
                  ))
              .toList(),
          validator: (value) {
            if (value == null) {
              return 'Please select gender.';
            }
          },
          dropdownFullScreen: true,
          onChanged: (value) {},
          onSaved: (value) {
            selectedValue = value.toString();
          },
        ),
      ),
    );
  }
}```

Build Error when importing package

Hey, Package looks awesome

However I am not able to use it in my app.
Whenever I import it I get the following error during build
Can you see the stack trace and if possible help me with it.
Thanks

Stack Trace

/C:/Installs/flutter_windows_1.22.2-stable/flutter/.pub-cache/hosted/pub.dartlang.org/dropdown_button2-1.0.7/lib/dropdown_button2.dart:172:20: Error: Type 'ShortcutActivator' not found.
  static const Map<ShortcutActivator, Intent> _webShortcuts =
                   ^^^^^^^^^^^^^^^^^
/C:/Installs/flutter_windows_1.22.2-stable/flutter/.pub-cache/hosted/pub.dartlang.org/dropdown_button2-1.0.7/lib/dropdown_button2.dart:173:8: Error: 'ShortcutActivator' isn't a type.
      <ShortcutActivator, Intent>{
       ^^^^^^^^^^^^^^^^^
/C:/Installs/flutter_windows_1.22.2-stable/flutter/.pub-cache/hosted/pub.dartlang.org/dropdown_button2-1.0.7/lib/dropdown_button2.dart:176:5: Error: Method not found: 'SingleActivator'.
    SingleActivator(LogicalKeyboardKey.arrowDown):

    ^^^^^^^^^^^^^^^
/C:/Installs/flutter_windows_1.22.2-stable/flutter/.pub-cache/hosted/pub.dartlang.org/dropdown_button2-1.0.7/lib/dropdown_button2.dart:178:5: Error: Method not found: 'SingleActivator'.

    SingleActivator(LogicalKeyboardKey.arrowUp):
    ^^^^^^^^^^^^^^^
/C:/Installs/flutter_windows_1.22.2-stable/flutter/.pub-cache/hosted/pub.dartlang.org/dropdown_button2-1.0.7/lib/dropdown_button2.dart:172:20: Error: 'ShortcutActivator' isn't a type.
  static const Map<ShortcutActivator, Intent> _webShortcuts =
                   ^^^^^^^^^^^^^^^^^
/C:/Installs/flutter_windows_1.22.2-stable/flutter/.pub-cache/hosted/pub.dartlang.org/dropdown_button2-1.0.7/lib/dropdown_button2.dart:222:26: Error: The getter 'enabled' isn't defined for the class 'DropdownMenuItem<T>'.
- 'DropdownMenuItem' is from 'package:flutter/src/material/dropdown.dart' ('/C:/Installs/flutter_windows_1.22.2-stable/flutter/packages/flutter/lib/src/material/dropdown.dart').
package:flutter/…/material/dropdown.dart:1
Try correcting the name to the name of an existing getter, or defining a getter or field named 'enabled'.
    if (dropdownMenuItem.enabled) {

                         ^^^^^^^
/C:/Installs/flutter_windows_1.22.2-stable/flutter/.pub-cache/hosted/pub.dartlang.org/dropdown_button2-1.0.7/lib/dropdown_button2.dart:233:36: Error: The getter 'enabled' isn't defined for the class 'DropdownMenuItem<T>'.
- 'DropdownMenuItem' is from 'package:flutter/src/material/dropdown.dart' ('/C:/Installs/flutter_windows_1.22.2-stable/flutter/packages/flutter/lib/src/material/dropdown.dart').
package:flutter/…/material/dropdown.dart:1

Try correcting the name to the name of an existing getter, or defining a getter or field named 'enabled'.
    if (kIsWeb && dropdownMenuItem.enabled) {
                                   ^^^^^^^
/C:/Installs/flutter_windows_1.22.2-stable/flutter/.pub-cache/hosted/pub.dartlang.org/dropdown_button2-1.0.7/lib/dropdown_button2.dart:1314:26: Error: The getter 'enabled' isn't defined for the class 'DropdownMenuItem<T>'.
- 'DropdownMenuItem' is from 'package:flutter/src/material/dropdown.dart' ('/C:/Installs/flutter_windows_1.22.2-stable/flutter/packages/flutter/lib/src/material/dropdown.dart').
package:flutter/…/material/dropdown.dart:1
Try correcting the name to the name of an existing getter, or defining a getter or field named 'enabled'.
                    item.enabled && item.value == widget.value)

                         ^^^^^^^


Flutter doctor output

[√] Flutter (Channel stable, 2.2.3, on Microsoft Windows [Version 10.0.19043.1415], locale en-IN)
    • Flutter version 2.2.3 at C:\Installs\flutter_windows_1.22.2-stable\flutter
    • Framework revision f4abaa0735 (6 months ago), 2021-07-01 12:46:11 -0700
    • Engine revision 241c87ad80
    • Dart version 2.13.4

[√] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
    • Android SDK at C:\Users\kohli\AppData\Local\Android\sdk
    • Platform android-30, build-tools 30.0.2
    • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)
    • All Android licenses accepted.

[√] Chrome - develop for the web
    • Chrome at C:\Program Files\Google\Chrome\Application\chrome.exe

[√] Android Studio (version 4.1.0)
    • Android Studio at C:\Program Files\Android\Android Studio
    • Flutter plugin can be installed from:
       https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
       https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)

[√] IntelliJ IDEA Community Edition (version 2020.3)
    • IntelliJ at C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2020.3.2
    • Flutter plugin can be installed from:
       https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
       https://plugins.jetbrains.com/plugin/6351-dart

[√] VS Code (version 1.63.2)
    • VS Code at C:\Users\kohli\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.29.0

[√] Connected device (3 available)
    • sdk gphone x86 (mobile) • emulator-5554 • android-x86    • Android 11 (API 30) (emulator)
    • Chrome (web)            • chrome        • web-javascript • Google Chrome 96.0.4664.110
    • Edge (web)              • edge          • web-javascript • Microsoft Edge 96.0.1054.34

• No issues found!

Dropdownbutton not displaying properly

tempFileForShare_20220606-121137

It was working perfectly yesterday night, but this morning, I was faced with this error, after building it on debug mode.
Please check for this issue, thanks. Hope it will be resolved in the next update. Great package right here

Item list width issue

Hi @AhmedLSayed9 at first thank you so much for making such helpful widget. Currently I am facing one issue with this widget.

Screenshot 2021-12-06 at 10 15 00 PM

As you can see image options list width not same as dropdown widget. I want to make options list same width as dropdown widget.

I have tried itemWidth etc but not worked.

Would you like to help me how to fix that?

Thank you

Null check operator used on a null value

Getting the following error in iOS simulator.

flutter: Null check operator used on a null value
flutter: 
#0      DropdownButton2State.didChangeMetrics (package:dropdown_button2/dropdown_button2.dart:1544:20)
#1      WidgetsBinding.handleMetricsChanged (package:flutter/src/widgets/binding.dart:570:16)
#2      _rootRun (dart:async/zone.dart:1426:13)
#3      _CustomZone.run (dart:async/zone.dart:1328:19)
#4      _CustomZone.runGuarded (dart:async/zone.dart:1236:7)
#5      _invoke (dart:ui/hooks.dart:151:10)
#6      PlatformDispatcher._updateWindowMetrics (dart:ui/platform_dispatcher.dart:236:5)
#7      _updateWindowMetrics (dart:ui/hooks.dart:33:31)

how put items center above dropdown

The dropdown items always when the width is reduced are located fixed in a predetermined position how can it be centered?.
and it is possible to reverse the animation effect when the menu is closed

RenderFlex overflowed error

In Dropdown2 items if we add
DropdownButton2( dropdownWidth: MediaQuery.of(context).size.width * 0.6, buttonWidth: MediaQuery.of(context).size.width * 0.6, ... DropdownMenuItem<String>( child: Text( list[i], style: GoogleFonts.inter(), overflow: TextOverflow.ellipsis, maxLines: 1, ), value: list[i], ), ...
and one of the item has like 200 characters then DropdownMenuItem rendered it with overflow type ellipses but button width will show error of renderFlex overflow.
IMG_4269

Default width error

@AhmedLSayed9 Hello, I have a small question/remark. If you do not set the width of the button and dropdownlist, then the width of the button is taken as the maximum width of the child element from the list (correct me if I'm wrong). But at the same time, the dropdownlist has some paddings or margins (I did not find their variables) that are not added to this width.

As a result, it turns out that this element does not completely fit into the dropdown and is cut off. If the list of items is static, then this is easily solved by setting specific sizes, but if the list for the dropdown comes from the server and can change, then a problem appears.

Рисунок1

Scrollbar Assertion Failed on clicking dropdown

This error appears in my output every time I click on a drop down from this library. There isn't anything fancy on my drop down. This happens on Windows and Web. The error itself does not affect the functioning of the drop down, however it is quite annoying to see it every time I click something. If there is a way to silence it or to solve the problem, please let me know.

Here is my build function:

Widget build(BuildContext context) {
    return ValueListenableBuilder(
      valueListenable: globals.app.homePageStateNotifier,
      builder: (context, HomePageData newState, _) {
        newState.saveData();
        loadState(newState);
        return Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Text(
                'You have pushed the button this many times:',
              ),
              Text(
                '$_counter',
                style: Theme.of(context).textTheme.headline4,
              ),
              DropdownButtonHideUnderline(
                child: DropdownButton2(
                  items: _themeDropdown,
                  value: _selectedItem,
                  onChanged: (MaterialColor? newval) {
                    _themeChanged(newval);
                  },
                  isExpanded: true,
                  buttonDecoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(15),
                    border: Border.all(
                      color: Colors.grey,
                    ),
                  ),
                  dropdownDecoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(15),
                    border: Border.all(
                      color: Colors.grey,
                    ),
                  ),
                  buttonWidth: 300,
                ),
              ),
            ],
          ),
        );
      },
    );
  }

Here is the output for Windows & Web:

Windows (Desktop)

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: 'package:flutter/src/widgets/scroll_controller.dart': Failed assertion: line 151 pos 12: '_positions.isNotEmpty': ScrollController not attached to any scroll views.
#0      _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:51:61)
#1      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:40:5)
#2      ScrollController.animateTo (package:flutter/src/widgets/scroll_controller.dart:151:12)
#3      _DropdownMenuItemButtonState._handleFocusChange (package:dropdown_button2/dropdown_button2.dart:144:38)
#4      _InkResponseState.handleFocusUpdate (package:flutter/src/material/ink_well.dart:1028:27)
#5      _FocusState._handleFocusChanged (package:flutter/src/widgets/focus_scope.dart:632:27)
#6      ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:351:24)
#7      FocusNode._notify (package:flutter/src/widgets/focus_manager.dart:1038:5)
#8      FocusManager._applyFocusChange (package:flutter/src/widgets/focus_manager.dart:1804:12)
#9      _microtaskLoop (dart:async/schedule_microtask.dart:40:21)
#10     _startMicrotaskLoop (dart:async/schedule_microtask.dart:49:5)

Web (Chrome)

Error: Assertion failed: file:///D:/GitHub/flutter/packages/flutter/lib/src/widgets/scroll_controller.dart:151:12
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart
266:49  throw_
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart
29:3    assertFailed
packages/flutter/src/widgets/scroll_controller.dart 151:23
animateTo
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 84:54
runBody
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 123:5
_async
packages/flutter/src/widgets/scroll_controller.dart 146:25
animateTo
packages/dropdown_button2/dropdown_button2.dart 144:20
[_handleFocusChange]
packages/flutter/src/material/ink_well.dart 1028:27
handleFocusUpdate
packages/flutter/src/widgets/focus_scope.dart 632:27
[_handleFocusChanged]
packages/flutter/src/foundation/change_notifier.dart 351:24
notifyListeners
packages/flutter/src/widgets/focus_manager.dart 1038:5
[_notify]
packages/flutter/src/widgets/focus_manager.dart 1804:11
[_applyFocusChange]
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/schedule_microtask.dart 40:11
_microtaskLoop
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/async/schedule_microtask.dart 49:5
_startMicrotaskLoop
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 166:15
<fn>

Error styling hint

When I try to style hint I get the error: The argument type 'Text' can't be assigned to the parameter type 'String'

Error on class: dropdown_button2.dart on _webShortcuts declaration

Hi this widget have some errors on line 159 :

static const Map<ShortcutActivator, Intent> _webShortcuts =
      <ShortcutActivator, Intent>{
    // On the web, up/down don't change focus, *except* in a <select>
    // element, which is what a dropdown emulates.
    SingleActivator(LogicalKeyboardKey.arrowDown):
        DirectionalFocusIntent(TraversalDirection.down),
    SingleActivator(LogicalKeyboardKey.arrowUp):
        DirectionalFocusIntent(TraversalDirection.up),
  };

** error: The name 'ShortcutActivator' isn't a type so it can't be used as a type argument.
Try correcting the name to an existing type, or defining a type named 'ShortcutActivator'

see image
imagen

Can check if latest version is stable?

openWithLongPress seems not working

Hi, I want to make the DropdownButtonFormField to be long press in order to open the dropdown menu, but the openWithLongPress seems not working. I still able to tap it when openWithLongPress is true and long press is nothing happen. Where did I do wrong? Any help will be appreciated. Thanks.

Here is the code for the DropdownButtonFormField:

  final FormFieldValidator<T>? validator;
  final List<FastDropDownMenuItem<T>> items;
  final String? labelText;
  final String? helperText;
  final String? hintText;
  final T? initialValue;
  final ValueChanged<T?> onChanged;
  final Widget? suffixIcon;
  final double? itemHeight;
  final InputBorder border;
  final InputBorder focusedBorder;
  final String? previousInfo;
  final bool isNewAnimalForm;

  const FastDropdownButtonFormField({
    Key? key,
    required this.items,
    this.labelText,
    required this.onChanged,
    this.helperText,
    this.hintText,
    this.initialValue,
    this.itemHeight,
    this.suffixIcon,
    this.validator,
    this.focusedBorder =
        const OutlineInputBorder(borderSide: BorderSide(color: Colors.black54)),
    this.border =
        const OutlineInputBorder(borderSide: BorderSide(color: Colors.black12)),
    this.previousInfo,
    this.isNewAnimalForm = false,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Stack(
      clipBehavior: Clip.none,
      children: [
        Padding(
          padding: const EdgeInsets.only(bottom: 12.0, top: 7.0),
          child: DropdownButtonFormField2(
            autovalidateMode: AutovalidateMode.onUserInteraction,
            decoration: InputDecoration(
              filled: true,
              helperStyle: const TextStyle(fontSize: 14),
              helperText: helperText,
              suffixIcon: suffixIcon,
              contentPadding: const EdgeInsets.only(left: 8, bottom: 8),
              floatingLabelBehavior: FloatingLabelBehavior.always,
              hintStyle: const TextStyle(color: Colors.black54, fontSize: 16),
              fillColor: Colors.white,
              focusedBorder: focusedBorder,
              border: border,
            ),
            hint: hintText == null
                ? null
                : Text(hintText!, style: const TextStyle(color: Colors.black)),
            iconEnabledColor: fsGreen,
            isDense: false,
            isExpanded: true,
            items: items,
            itemHeight: itemHeight ?? kMinInteractiveDimension,
            onChanged: onChanged,
            openWithLongPress: true,
            validator: validator,
            value: initialValue,
            customItemsIndexes: [items.length],
          ),
        ),
      ],
    );
  }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.