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

Overview

Flutter DropdownButton2

Intro

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

Features

  • Dropdown menu always open below the button and you can edit its position by using the offset parameter.
  • You can make the menu open above the button by setting showAboveButton to true.
  • You can edit (button, menu and menu items) height, width and decoration as you want.
  • You can align hint or value and customize them.
  • You can edit the scrollbar's radius,thickness and isAlwaysShow.
  • You can specify 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 last selected item and show it at the middle of the menu if possible.
  • Wrap the 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 as a popup menu button by using the parameter customButton. You can pass Icon,Image or anything you want and customize it as shown in the examples.
  • You can make the popup menu open onLongPress instead of onTap by setting openWithLongPress parameter to true.
  • You can Add dividers to the popup menu with different height by passing dividers indexes to customItemsIndexes and the height to customItemsHeight.
  • You can also use DropdownButtonFormField2 the same way with all options above.
  • Use decoration parameter for the DropdownButtonFormField2 to add labelText,fillColor and more.
  • You can customize the DropdownButtonFormField2 width by wrapping it with SizedBox and give it the width you want.

Installation

add this line to pubspec.yaml

dependencies:

  dropdown_button2: ^1.0.0

import package

import 'package:dropdown_button2/dropdown_button2.dart';

Usage & Examples

  1. Simple DropdownButton2 without too many specifications:

Image

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

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: DropdownButtonHideUnderline(
        child: DropdownButton2(
          hint: Text(
            'Select Item',
            style: TextStyle(
              fontSize: 14,
              color: Theme
                  .of(context)
                  .hintColor,
            ),
          ),
          items: items
              .map((item) =>
              DropdownMenuItem<String>(
                value: item,
                child: Text(
                  item,
                  style: const TextStyle(
                    fontSize: 14,
                  ),
                ),
              ))
              .toList(),
          value: selectedValue,
          onChanged: (value) {
            setState(() {
              selectedValue = value as String;
            });
          },
          buttonHeight: 40,
          buttonWidth: 140,
          itemHeight: 40,
          itemWidth: 140,
        ),
      ),
    ),
  );
}
  1. More customized DropdownButton2 using DropdownButton2 directly:

Image

 String? selectedValue;
List<String> items = [
  'Item1',
  'Item2',
  'Item3',
  'Item4',
  'Item5',
  'Item6',
  'Item7',
  'Item8',
];

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: DropdownButtonHideUnderline(
        child: DropdownButton2(
          isExpanded: true,
          hint: Row(
            children: const [
              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((item) =>
              DropdownMenuItem<String>(
                value: item,
                child: Text(
                  item,
                  style: const TextStyle(
                    fontSize: 14,
                    fontWeight: FontWeight.bold,
                    color: Colors.white,
                  ),
                  overflow: TextOverflow.ellipsis,
                ),
              ))
              .toList(),
          value: selectedValue,
          onChanged: (value) {
            setState(() {
              selectedValue = value as String;
            });
          },
          icon: const Icon(
            Icons.arrow_forward_ios_outlined,
          ),
          iconSize: 14,
          iconEnabledColor: Colors.yellow,
          iconDisabledColor: Colors.grey,
          buttonHeight: 50,
          buttonWidth: 160,
          buttonPadding: const EdgeInsets.only(left: 14, right: 14),
          buttonDecoration: BoxDecoration(
            borderRadius: BorderRadius.circular(14),
            border: Border.all(
              color: Colors.black26,
            ),
            color: Colors.redAccent,
          ).copyWith(
            boxShadow: kElevationToShadow[2],
          ),
          itemHeight: 40,
          itemWidth: 200,
          itemPadding: const EdgeInsets.only(left: 14, right: 14),
          dropdownMaxHeight: 200,
          dropdownPadding: null,
          dropdownBorderRadius: BorderRadius.circular(14),
          dropdownBorder: null,
          dropdownColor: Colors.redAccent,
          elevation: 8,
          scrollbarRadius: const Radius.circular(40),
          scrollbarThickness: 6,
          scrollbarAlwaysShow: true,
          offset: const Offset(-20, 0),
        ),
      ),
    ),
  );
}
  1. More customized DropdownButton2 using the reusable Custom widget attached below:

Image

String? selectedValue;
List<String> items = [
  'Item1',
  'Item2',
  'Item3',
  'Item4',
  'Item5',
  'Item6',
  'Item7',
  'Item8',
];

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Center(
      child: CustomDropdownButton2(
        hint: 'Select Item',
        dropdownItems: items,
        value: selectedValue,
        onChanged: (value) {
          setState(() {
            selectedValue = value;
          });
        },
      ),
    ),
  );
}
  1. DropdownButton2 as Popup menu button using customButton parameter and adding custom items with different height like dividers:

Example 1 using icon:

Image

class CustomButtonTest extends StatefulWidget {
  const CustomButtonTest({Key? key}) : super(key: key);

  @override
  State<CustomButtonTest> createState() => _CustomButtonTestState();
}

class _CustomButtonTestState extends State<CustomButtonTest> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: DropdownButtonHideUnderline(
          child: DropdownButton2(
            customButton: const Icon(
              Icons.list,
              size: 46,
              color: Colors.red,
            ),
            customItemsIndexes: const [3],
            customItemsHeight: 8,
            items: [
              ...MenuItems.firstItems.map(
                    (item) =>
                    DropdownMenuItem<MenuItem>(
                      value: item,
                      child: MenuItems.buildItem(item),
                    ),
              ),
              const DropdownMenuItem<Divider>(enabled: false, child: Divider()),
              ...MenuItems.secondItems.map(
                    (item) =>
                    DropdownMenuItem<MenuItem>(
                      value: item,
                      child: MenuItems.buildItem(item),
                    ),
              ),
            ],
            onChanged: (value) {
              MenuItems.onChanged(context, value as MenuItem);
            },
            itemHeight: 48,
            itemWidth: 160,
            itemPadding: const EdgeInsets.only(left: 16, right: 16),
            dropdownPadding: const EdgeInsets.symmetric(vertical: 6),
            dropdownBorderRadius: BorderRadius.circular(4),
            dropdownBorder: null,
            dropdownColor: Colors.redAccent,
            elevation: 8,
            offset: const Offset(0, 8),
          ),
        ),
      ),
    );
  }
}

class MenuItem {
  final String text;
  final IconData icon;

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

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,
        ),
        Text(
          item.text,
          style: const TextStyle(
            color: Colors.white,
          ),
        ),
      ],
    );
  }

  static 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 CustomButtonTest extends StatefulWidget {
  const CustomButtonTest({Key? key}) : super(key: key);

  @override
  State<CustomButtonTest> createState() => _CustomButtonTestState();
}

class _CustomButtonTestState extends State<CustomButtonTest> {
  @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: NetworkImage(
                    'https://cdn.pixabay.com/photo/2020/05/11/06/20/city-5156636_960_720.jpg',
                  ),
                  fit: BoxFit.cover,
                ),
              ),
            ),
            openWithLongPress: true,
            customItemsIndexes: const [3],
            customItemsHeight: 8,
            items: [
              ...MenuItems.firstItems.map(
                        (item) =>
                        DropdownMenuItem<MenuItem>(
                          value: item,
                          child: MenuItems.buildItem(item),
                        ),
              ),
              const DropdownMenuItem<Divider>(enabled: false, child: Divider()),
              ...MenuItems.secondItems.map(
                        (item) =>
                        DropdownMenuItem<MenuItem>(
                          value: item,
                          child: MenuItems.buildItem(item),
                        ),
              ),
            ],
            onChanged: (value) {
              MenuItems.onChanged(context, value as MenuItem);
            },
            itemHeight: 48,
            itemWidth: 160,
            itemPadding: const EdgeInsets.only(left: 16, right: 16),
            dropdownPadding: const EdgeInsets.symmetric(vertical: 6),
            dropdownBorderRadius: BorderRadius.circular(4),
            dropdownBorder: null,
            dropdownColor: Colors.redAccent,
            elevation: 8,
            offset: const Offset(40, -4),
          ),
        ),
      ),
    );
  }
}

class MenuItem {
  final String text;
  final IconData icon;

  const MenuItem({
    required this.text,
    required this.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,
        ),
        Text(
          item.text,
          style: const TextStyle(
            color: Colors.white,
          ),
        ),
      ],
    );
  }

  static 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;
    }
  }
}

Custom DropdownButton2 Widget

class CustomDropdownButton2 extends StatelessWidget {
  final String hint;
  final String? value;
  final List<String> dropdownItems;
  final ValueChanged<String?>? onChanged;
  final Alignment? hintAlignment;
  final Alignment? valueAlignment;
  final double? buttonHeight, buttonWidth;
  final EdgeInsetsGeometry? buttonPadding;
  final Decoration? buttonDecoration;
  final int? buttonElevation;
  final Widget? icon;
  final double? iconSize;
  final Color? iconEnabledColor;
  final Color? iconDisabledColor;
  final double? itemHeight, itemWidth;
  final EdgeInsetsGeometry? itemPadding;
  final double? dropdownHeight;
  final EdgeInsetsGeometry? dropdownPadding;
  final BorderRadius? dropdownBorderRadius;
  final BoxBorder? dropdownBorder;
  final int? dropdownElevation;
  final Color? dropdownColor;
  final Radius? scrollbarRadius;
  final double? scrollbarThickness;
  final bool? scrollbarAlwaysShow;
  final Offset? offset;

  const CustomDropdownButton2({
    required this.hint,
    required this.value,
    required this.dropdownItems,
    required this.onChanged,
    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.itemWidth,
    this.itemPadding,
    this.dropdownHeight,
    this.dropdownPadding,
    this.dropdownBorderRadius,
    this.dropdownBorder,
    this.dropdownElevation,
    this.dropdownColor,
    this.scrollbarRadius,
    this.scrollbarThickness,
    this.scrollbarAlwaysShow,
    this.offset,
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return DropdownButtonHideUnderline(
      child: DropdownButton2(
        isExpanded: true,
        //To avoid long text overflowing.
        hint: Container(
          alignment: hintAlignment,
          child: Text(
            hint,
            overflow: TextOverflow.ellipsis,
            maxLines: 1,
            style: TextStyle(
              fontSize: 14,
              color: Theme
                      .of(context)
                      .hintColor,
            ),
          ),
        ),
        value: value,
        items: dropdownItems
                .map((item) =>
                DropdownMenuItem<String>(
                  value: item,
                  child: Container(
                    alignment: valueAlignment,
                    child: Text(
                      item,
                      overflow: TextOverflow.ellipsis,
                      maxLines: 1,
                      style: const TextStyle(
                        fontSize: 14,
                      ),
                    ),
                  ),
                ))
                .toList(),
        onChanged: onChanged,
        icon: icon ?? const Icon(Icons.arrow_forward_ios_outlined),
        iconSize: iconSize ?? 12,
        iconEnabledColor: iconEnabledColor,
        iconDisabledColor: iconDisabledColor,
        buttonHeight: buttonHeight ?? 40,
        buttonWidth: buttonWidth ?? 140,
        buttonPadding:
        buttonPadding ?? const EdgeInsets.only(left: 14, right: 14),
        buttonDecoration: buttonDecoration ??
                BoxDecoration(
                  borderRadius: BorderRadius.circular(14),
                  border: Border.all(
                    color: Colors.black45,
                  ),
                  color: Theme
                          .of(context)
                          .canvasColor,
                ).copyWith(
                  boxShadow: kElevationToShadow[buttonElevation ?? 0],
                ),
        itemHeight: itemHeight ?? 40,
        itemWidth: itemWidth ?? 140,
        itemPadding: itemPadding ?? const EdgeInsets.only(left: 14, right: 14),
        dropdownMaxHeight: dropdownHeight ?? 240,
        //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.
        dropdownPadding: dropdownPadding,
        dropdownBorderRadius: dropdownBorderRadius ?? BorderRadius.circular(14),
        dropdownBorder: dropdownBorder,
        //Default has no border.
        dropdownColor: dropdownColor ?? Theme
                .of(context)
                .canvasColor,
        elevation: dropdownElevation ?? 8,
        scrollbarRadius: scrollbarRadius ?? const Radius.circular(40),
        scrollbarThickness: scrollbarThickness,
        scrollbarAlwaysShow: scrollbarAlwaysShow,
        offset: offset,
        //Null or Offset(0, 0) will open just under the button. You can edit as you want.
        showAboveButton: false, //Default is false to show menu below button
      ),
    );
  }
}

Thanks

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

LICENSE: MIT

Comments
  • I am using dropdown searchable but searchable is list is come from network call

    I am using dropdown searchable but searchable is list is come from network call

    Passing selected items as a constructor but it will be not working. Normal situation it will be work. When we make this one as a reusable widget then it will be not work selected value is not setted.

    Below sample code added

      Future<void> searchModality(String searchKey) async {
    /// Network call
        List<String> list = await getModality(context, searchKey);
        commonProvider.updateModality(CustomObj.toMap(list));
        print("List $list");
        commonProvider.refreshWidget();
      }
    
    
    Consumer<CommonWidgetRefreshProvider>(
                  builder: (context, value, child) {
                return Container(
                  width: 130,
                  child: CustomSearchableDialog(
                    finalValueSelection: (p0) {
                      commonProvider.updateSelectedModality(p0);
                    },
                    dropDownValue: commonProvider.modalityList,
                    searchCallBack: (searchKey) {
                      searchModality(searchKey);
                    },
                    selectedItems: commonProvider.selectedItemsModality,
                  ),
                );
    })
    
    class CustomSearchableDialog extends StatefulWidget {
      final double searchFontSize;
      final FontWeight searchFontWeight;
      final String searchFontFamily;
      final Color searchTextColor;
    
      final String hintSearch;
      final double hintSearchFontSize;
      final FontWeight hintSearchFontWeight;
      final String hintSearchFontFamily;
      final Color hintSearchTextColor;
    
      final Function(String)? searchCallBack;
      final Function(List<dynamic>)? finalValueSelection;
      final List<dynamic> dropDownValue;
      final List<dynamic> selectedItems;
    
      final Color listItemTextColor;
      final double listItemFontSize;
      final FontWeight listItemFontWeight;
      final String listItemFontFamily;
    
      final Color checkMarkColor;
      final double checkMarkSize;
    
      const CustomSearchableDialog(
          {this.hintSearch = "Search for",
          this.hintSearchFontSize = FONT_SIZE_REGULAR,
          this.hintSearchFontWeight = FontWeight.w400,
          this.hintSearchFontFamily = MONTSERRAT_REGULAR,
          this.hintSearchTextColor = black11,
          this.searchFontSize = FONT_SIZE_REGULAR,
          this.searchFontWeight = FontWeight.w400,
          this.searchFontFamily = MONTSERRAT_REGULAR,
          this.searchTextColor = GREY_SHADE,
          this.listItemTextColor = ASSIGNEE_COLOR,
          this.listItemFontSize = FONT_SIZE_REGULAR,
          this.listItemFontWeight = FontWeight.w400,
          this.listItemFontFamily = MONTSERRAT_REGULAR,
          this.checkMarkColor = darkblue,
          this.checkMarkSize = 16,
          this.dropDownValue = const [],
          this.selectedItems = const [],
          this.finalValueSelection,
          this.searchCallBack,
          Key? key})
          : super(key: key);
    
      @override
      _CustomSearchableDialogState createState() => _CustomSearchableDialogState();
    }
    
    class _CustomSearchableDialogState extends State<CustomSearchableDialog> {
      late CommonWidgetRefreshProvider provider;
    
      List<dynamic> localList = [{"id": "", "name": ""}];
    
      final TextEditingController searchController = TextEditingController();
      bool isExpanded = false;
      final dropdownKey = GlobalKey<DropdownButton2State>();
      void Function(void Function())? functionCallback;
      List<dynamic> selectedItems = [];
    
      @override
      void initState() {
        super.initState();
        provider = Provider.of<CommonWidgetRefreshProvider>(context, listen: false);
        print("init state expanded $isExpanded");
      }
    
      @override
      void didUpdateWidget(CustomSearchableDialog oldWidget) {
        super.didUpdateWidget(oldWidget);
        if(oldWidget.selectedItems != selectedItems){
          print("ITs changed item");
        }else{
          print("ITs item is same");
        }
        SchedulerBinding.instance?.addPostFrameCallback((_) {
          provider.refreshWidget();
        });
      }
    
      @override
      void dispose() {
        searchController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Consumer<CommonWidgetRefreshProvider>(
            builder: (context, value, child) {
          return DropdownButtonHideUnderline(
            child: DropdownButton2(
              key: dropdownKey,
              isExpanded: true,
              dropdownWidth: 250,
              hint: FilterTitleWidget(
                  titleText: DATE_STRING,
                  icon: isExpanded ? Icons.expand_less : Icons.expand_more),
              icon: Container(),
              items: widget.dropDownValue
                  .map((item) => DropdownMenuItem<dynamic>(
                        value: item,
                        enabled: false,
                        child: StatefulBuilder(
                          builder: (BuildContext context,
                              void Function(void Function()) change) {
                            functionCallback = change;
                            final _isSelected = selectedItems.contains(item);
                            return InkWell(
                              onTap: () {
                                _isSelected
                                    ? selectedItems.remove(item)
                                    : selectedItems.add(item);
                                change(() {});
                              },
                              child: Container(
                                height: double.infinity,
                                padding: const EdgeInsets.symmetric(
                                    horizontal: 16.0),
                                color: _isSelected
                                    ? SELECTED_BACKGROUND_COLOR
                                    : null,
                                child: Row(
                                  mainAxisAlignment:
                                  MainAxisAlignment.spaceBetween,
                                  crossAxisAlignment:
                                  CrossAxisAlignment.center,
                                  children: [
                                    Text(
                                      (item is CustomObj)
                                          ? item.name
                                          : item['name'],
                                      style: TextStyle(
                                          fontSize: widget.listItemFontSize,
                                          color: widget.listItemTextColor,
                                          fontFamily:
                                          widget.listItemFontFamily,
                                          fontWeight:
                                          widget.listItemFontWeight),
                                    ),
                                    _isSelected
                                        ? Icon(Icons.check,
                                        color: widget.checkMarkColor,
                                        size: widget.checkMarkSize)
                                        : const SizedBox(),
                                  ],
                                ),
                              ),
                            );
                          },
                        ),
                      ))
                  .toList(),
              onChanged: (dynamic value) {},
              buttonHeight: 40,
              itemHeight: 40,
              alignment: Alignment.center,
              dropdownMaxHeight: 422,
              searchController: searchController,
              dropdownDecoration: BoxDecoration(
                borderRadius: BorderRadius.all(Radius.circular(8)),
                color: Colors.white,
                boxShadow: [
                  BoxShadow(
                    offset: Offset(0, 0),
                    blurRadius: 1,
                    spreadRadius: 1,
                    color: black14,
                  ),
                ],
              ),
              searchInnerWidget: Container(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.start,
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Container(
                      padding: const EdgeInsets.symmetric(horizontal: 16),
                      alignment: Alignment.topCenter,
                      child: TextFormField(
                        controller: searchController,
                        style: TextStyle(
                            fontSize: widget.searchFontSize,
                            fontFamily: widget.searchFontFamily,
                            fontWeight: widget.searchFontWeight,
                            color: widget.searchTextColor),
                        onChanged: (value) async {
                          print("On text changed $value");
                          if (widget.searchCallBack != null) {
                            widget.dropDownValue.clear();
                            widget.searchCallBack!(value);
                          }
                        },
                        decoration: InputDecoration(
                          isDense: true,
                          contentPadding: EdgeInsets.only(left: 8, top: 16),
                          suffixIcon: Icon(Icons.search_rounded),
                          hintText: widget.hintSearch,
                          hintStyle: TextStyle(
                              fontSize: widget.hintSearchFontSize,
                              fontWeight: widget.hintSearchFontWeight,
                              fontFamily: widget.hintSearchFontFamily,
                              color: widget.hintSearchTextColor),
                        ),
                      ),
                    ),
                          );}
                        );
                      },
                    )
                  ],
                ),
              ),
              onMenuStateChange: (isOpen) {
                isExpanded = isOpen;
                if (!isOpen) {
                  if (widget.finalValueSelection != null) {
                    widget.finalValueSelection!(selectedItems);
                  }
                } else {
    //              provider.refreshWidget();
       //           dropdownKey.currentState?.setState(() {});
                }
              },
            ),
          );
        });
      }
    }
    
    invalid 
    opened by radheyshyamjat 22
  • Setting a decent label is a nightmare!

    Setting a decent label is a nightmare!

    Hi,

    Thanks for such a nice and customizable widget.

    There is just one issue that at least I couldn't fix even after trying every option that seemed relevant.

    In case of DropdownButtonTextField2, when we add label in the decoration, it aligns to the extreme left. If we try to apply a padding via contentPadding, it duly applies to the label but then, the dropdown menu and the contents of the button also get padding on the left.

    After a lot of tries, I've finally decided to not use label at all.

    Can you pl look into it and provide a fix for that?

    Thanks

    documentation 
    opened by ShahoodulHassan 13
  • [Question] How can I minimize the button width by Icon only?

    [Question] How can I minimize the button width by Icon only?

    Hi,

    My purpose is to set the button only by an icon, so its dimensions will be according to the Icon/Widget. The meaning is that the width of the button should be shorter than the dropdown items width. Is it possible?

    Because the problem is that it set the min width of the button to be as the dropdown items width.

    Edited: I tried to set buttomWidth, but when I get low then a specific value (100) I get overflow and the button still active but become invisible. And I get errors in the log regarding size issue and null values.

    Thanks.

    documentation question 
    opened by burekas7 10
  •  Error: The method 'clampDouble' isn't defined for the class '_DropdownMenuPainter'.

    Error: The method 'clampDouble' isn't defined for the class '_DropdownMenuPainter'.

    As far as I can tell, clampDouble needs to be imported from the material_color_utilities package. I've created a branch which adds the dependency and implements in the problematic file, but I don't have rights to push the branch to the repo. If I can be added as a collaborator I'd be happy to submit the branch for review. Thanks.

    bug 
    opened by TRemigi 9
  • Update an Open Dropdown Menu

    Update an Open Dropdown Menu

    Right now I'm putting together a hacky solution using the search functionality provided in this framework.

    However, overall, I'd like the ability to dynamically update the dropdown menu items on a dropdown that's open.

    My use case is as follows:

    When the user first taps on the dropdown, we make an async call to get the items. While this call is occurring I show a single item, that represents the loading state. Once these items have been fetched, I'd like to push them into the already open menu. As of right now, I don't think there's a way to update the state of the DropDownMenu, besides hacking together something with the search controller (which is what I'm going to do)

    Edit: My hack unfortunately doesn't even work either :( This is because the searchController only goes through the items on the DropDownRoute, which is not updated with the latest items either

    enhancement 
    opened by cody1024d 8
  • [Request] Pinned items inside when they out of their parent constraints (X axis)

    [Request] Pinned items inside when they out of their parent constraints (X axis)

    Hi,

    Can you add an automatic behavior when the DropDownItems are outside the range on X axis to align it inside (As you do when it outside for y axis), without need to set the offset option.

    imageimage

    return Scaffold(
          appBar: AppBar(
            title: Text("Title"),
          ),
          body: SafeArea(
              child: Stack(
            children: [
              Positioned(
                bottom: 70,
                left: 30,
                child: DropdownButton2(
                  underline: Container(),
                  dropdownDecoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(14),
                    color: Colors.redAccent,
                  ),
                  dropdownWidth: 150,
                  customButton: Container(
                    padding: const EdgeInsets.all(8),
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(14),
                      border: Border.all(
                        color: Colors.black26,
                      ),
                      color: Colors.redAccent,
                    ),
                    child: const Icon(
                      Icons.sort,
                      color:
                          Colors.black, //Theme.of(context).primaryIconTheme.color,
                    ),
                  ),
                  items: const [
                    DropdownMenuItem(value: 1, child: Text("Item 1")),
                    DropdownMenuItem(value: 2, child: Text("Item 2")),
                    DropdownMenuItem(value: 3, child: Text("Item 3")),
                  ],
                  onChanged: (value) {},
                ),
              )
            ],
          )
        );
    
    bug question 
    opened by burekas7 8
  • how put items center above dropdown

    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

    documentation 
    opened by 3vilcrow 8
  • Dropdownbutton not displaying properly

    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

    bug 
    opened by Leo-Chan01 7
  • Item list width issue

    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

    bug 
    opened by iamfarmankhan 7
  • itemHeight null value is not available

    itemHeight null value is not available

    As per docs it states

    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].
    

    However the type of itemHeight is double, not double?, so I can't make each item different height. Am I missing something?

    documentation 
    opened by avdept 6
  • Tappable area not expandable

    Tappable area not expandable

    New version makes the tappable area shrink, which makes the widget unsuable. How it is now (1.7.1) - only hint widget height tappable: image

    How it should be (1.6.3) - whole button tappable: image

    It worked correctly in 1.6.3 and it doesn't in 1.7.1 (didn't check 1.7.0 though yet). Exactly same code and hint widget is Text()

    bug 
    opened by SirBarksALot 6
  • Change scrollbar colors

    Change scrollbar colors

    I need to personalise the scrollbar track and thumb colors, but I do not found a way to do that. Maybe You folks can help me with that?

    Is there a way to do it with the currently version or this is a feature that maybe need to be implemented?

    I could do that only changing in the app core theme for the entire project.

    enhancement 
    opened by danielesilvestre 1
Owner
AHMED ELSAYED
Flutter Developer
AHMED ELSAYED
Add an indicator for a progression. You can customize indicators (shape, color, ..)

dots_indicator Widget to display dots indicator to show a position (for a PageView for example). Installation You just need to add dots_indicator as a

Jean-Charles Moussé 139 Dec 1, 2022
Progress State Button - A customizable progress button for Flutter

Progress State Button - A customizable progress button for Flutter

Selim 108 Dec 12, 2022
Bubbleslider - A flutter package support a slider customize UI with bubble animation

bubble_slider This package support a slider customize UI with bubble animation.

MindInventory 11 Jul 26, 2022
A Flutter dropdown widget.

Flutter Dropdown_Below A Flutter Dropdown library which is customize flutter dropdownbutton widget. Options options description type required itemWidt

Denny Hong 27 Sep 7, 2022
Custom Layout with interactive add button to impove your UI and UX .

Interactive Add button layout Custom Layout with interactive add button to impove your UI and UX . the package is available here inspired from Oleg Fr

Dokkar Rachid Reda 20 Sep 13, 2021
A light weight library to easily manage a progress dialog with simple steps whenever you need to do it. You can easily show and hide it.

progress_dialog A light weight package to show progress dialog. As it is a stateful widget, you can change the text shown on the dialog dynamically. T

Mohammad Fayaz 202 Dec 11, 2022
An animated menu with both RTL and LTR direction support

animated_menu A new Flutter package project. Getting Started This project is a starting point for a Dart package, a library module containing code tha

Persian Flutter Community 5 Jan 31, 2022
A simple animated circular menu for Flutter, Adjustable radius, colors, alignment, animation curve and animation duration.

A simple animated circular menu for Flutter, Adjustable radius, colors, alignment, animation curve and animation duration. pub package Getting Started

Hasan Mohammed 91 Dec 20, 2022
Animated Menu in Flutter using radial.

Animated_radial_Menu_in_Flutter Animated Menu in Flutter using radial. Getting Started This project is a starting point for a Flutter application. A f

Habib ullah 4 Jul 18, 2022
A beautiful animated flutter widget package library. The tab bar will attempt to use your current theme out of the box, however you may want to theme it.

Motion Tab Bar A beautiful animated widget for your Flutter apps Preview: | | Getting Started Add the plugin: dependencies: motion_tab_bar: ^0.1.5 B

Rezaul Islam 237 Nov 15, 2022
A widget for stacking cards, which users can swipe horizontally and vertically with beautiful animations.

A widget for stacking cards, which users can swipe horizontally and vertically with beautiful animations.

HeavenOSK 97 Jan 6, 2023
In this repo you can expertise how to build various User Interface in Flutter

?? Flutter UI ?? Introduction The language used here is Dart, which is a object oriented programming language with the sdk called Flutter,It's a googl

navee-ramesh 17 Nov 5, 2022
A collection of Screens and attractive UIs built with Flutter ready to be used in your applications. No external libraries are used. Just download, add to your project and use.

Flutter Screens A collection of Login Screens, Buttons, Loaders and Widgets with attractive UIs, built with Flutter, ready to be used in your applicat

Samarth Agarwal 5k Dec 31, 2022
Loading widget based on a Flare animation, allow you to create beautiful custom loading widgets or dialogs

flare_loading Loading widget based on a Flare animation, allow you to create custom loading widgets or dialogs If you're using Rive instead of Flare p

Jimmy Aumard 25 Apr 16, 2021
A Flutter widget that easily adds the flipping animation to any widget

flip_card A component that provides a flip card animation. It could be used for hiding and showing details of a product. How to use import 'package:fl

Bruno Jurković 314 Dec 31, 2022
A widget that allow user resize the widget with drag

Flutter-Resizable-Widget A widget that allow user resize the widget with drag Note: this widget uses Getx Example bandicam.2021-11-11.12-34-41-056.mp4

MohammadAminZamani.afshar 22 Dec 13, 2022
A Flutter package allows you to Showcase/Highlight your widgets step by step.

ShowCaseView A Flutter package allows you to Showcase/Highlight your widgets step by step. Preview Installing Add dependency to pubspec.yaml Get the l

kirill 0 Dec 8, 2022
✨A clean and lightweight loading/toast widget for Flutter, easy to use without context, support iOS、Android and Web

Flutter EasyLoading English | 简体中文 Live Preview ?? https://nslog11.github.io/flutter_easyloading Installing Add this to your package's pubspec.yaml fi

nslog11 1k Jan 9, 2023
Help you to build pull-down refresh and pull-up loading in the simplest way.

frefresh Help you to build pull-down refresh and pull-up loading in the simplest way. Although unprecedented simplicity, but the effect is amazing. It

Fliggy Mobile 427 Nov 26, 2022