Dropdown  Button  in  Flutter

Dropdown Button in Flutter

Hey Guys,

Have you ever been stuck and you don't know the exact thing to do anymore, trust me, there are some bugs that won't just let you kill them (if you like use BagonπŸ˜‚)...

Well, I came across this bug 🐞 , yeah and I checked through Flutter documentation, Stack Overflow, and the like, couldn't get my solution.

I was able to figure it out after a couple of hours and I will like to share my solution. Also, I will be sharing some other solutions I came across just in case my solution doesn't fit. You can get all solutions in one stop, yah.

In this article, you will be learning how to use DropDownButton and learn various properties of it in flutter and also get the solution to common bugs associated with this widget.

Let's dive in...

What is a Dropdown Button πŸ’πŸ½β™‚οΈ? Dropdown Button is a Material Design button for selecting from a list of items.

       DropdownButton<String>(
          value: dropdownValue,
          icon: const Icon(Icons.arrow_downward),
           elevation: 16,
           style: const TextStyle(color: Colors.deepPurple),
         underline: Container(
          height: 2,
          color: Colors.deepPurpleAccent,
            ),
          onChanged: (String? value) {
         // This is called when the user selects an item.
        setState(() {
        dropdownValue = value!;
         });
         },
       items: list.map<DropdownMenuItem<String>>((String value) 
       {
        return DropdownMenuItem<String>(
       value: value,
        child: Text(value),
          );
        }).toList(),

The Dropdown Button has some properties and methods, To use this widget, you need to have a list of items that you will use in your dropdown. For the above example here is the list that was used

const List list = ['One', 'Two', 'Three'];

and when you run this in your flutter project, you will get something like this:
πŸ‘‡πŸΌπŸ‘‡πŸΌπŸ‘‡πŸΌπŸ‘‡πŸΌπŸ‘‡πŸΌπŸ‘‡πŸΌ

This image shows the result of the above codes

There you go!!!

Dropdown Button has a major issue!!! You have to use this widget right, and if not, you get stuck. This is the major issue with using a Dropdown Button.

Error meesage: Drop down Either or 2 more dropdown were detected with the same value????

Lets take this example as our point of focus.

      String _value1;
      String _value2;

     final List<String> nameList = <String>[
          "Name1",
          "Name2",
          "Name3",
          "Name4",
          "Name5",
          "Name6",
          "Name7",
           "Name8"
              ];

          @override
          Widget build(BuildContext context) {
            return Scaffold(
            appBar: AppBar(
            elevation: 2.0,
            title: Text('Hello'),
                ),
            body: ListView(
            children: <Widget>[
            Row(
                children: <Widget>[
                Text('Name: '),
                Center(
                child: DropdownButton(
                  value: _value1,
                onChanged: (value) {
                  setState(() {
                      _value1 = value;
                    });
                    },
                items: nameList.map(
                    (item) {
                  return DropdownMenuItem(
                    value: item,
                     child: new Text(item),
                      );
                      },
              ).toList(),    
              ),
            ),
            ],
            ),
          Row(
              children: <Widget>[
              Text('Name: '),
              Center(
              child: DropdownButton(
              value: _value2,
              onChanged: (value) {
          setState(() {
            _value2 = value;
                });
                },
          items: nameList.map(
        (item) {
              return DropdownMenuItem(
            value: item,
            child: new Text(item),
                );
                },
              ).toList(),
                    ),
                  ),
                ],
              ),
            ],
         ),
        backgroundColor: Colors.grey[200],
        );
      }
    }

One: Always make sure the value of the property "value" is not empty.

        DropdownButton(
            // Initial Value
           //note: this property called value is very important and shouldn't be omitted

            value: dropdownvalue,

            // Down Arrow Icon
            icon: const Icon(Icons.keyboard_arrow_down), 

          // Array list of items
        items: items.map((String items) {
          return DropdownMenuItem(
          value: items,
          child: Text(items),
          );
          }).toList(),

          // After selecting the desired option,it will
          // change button value to selected value
        onChanged: (String? newValue) {
        setState(() {
              dropdownvalue = newValue!;
                });
            },
        ),

Two: If the value is going to be promised, that is, at a later time the property will get its value, then check if the value is empty first, if it is empty replaced it with a default value.

        DropdownButton(
          value: _value1.isNotEmpty ? _value1 : "Selected Item", 
           // guard it with null if empty
            items: nameList.map((item) {
            return DropdownMenuItem(
            value: item,
            child: new Text(item),
                   );
              }).toList(), 
            );

Three: If you are getting your list from the database, make sure the function you are calling is not in your build context, it should be called once. And the reason why that is so is that when calling your API that will get the list within your build context, it gets called multiple times as you are using a set state to update the selected value.
Here is a complete example code πŸ‘‡πŸΌπŸ‘‡πŸΌπŸ‘‡πŸΌπŸ‘‡πŸΌπŸ‘‡πŸΌπŸ‘‡πŸΌπŸ‘‡πŸΌ

                class _ParentBankState extends 
                  State<ParentCategory> {
                  final _formKey = GlobalKey<FormState>();
                String? _selectedBankCategory;
                // List category = [];
                final List<String> _parentCategory = [
                "Select Category",
                ];

               //Make sure you do your calls inside the initState

              @override
              void initState() {

              //do your calls to get the list from your database 
              //here so that it will be called once...

              final category = context.read<AddMoneyCubit>. 
              ().loadBankList();
              super.initState();
              }

              @override
              Widget build(BuildContext context) {

                //Do not call your API here, why?
                //because build context get build multiple times and that 
                //will make your dropdown throw that error because it is 
                //seeing the value being used repeatedly...

                    var businessBankDropDown =
                  BlocBuilder<AddMoneyCubit, AddMoneyState>(
                    builder: (context, state) {
                        return Form(
                            key: _formKey,
                            child: ButtonTheme(
                                alignedDropdown: true,
                                 child: DropdownButtonHideUnderline(
                                    child: DropdownButton<String>(
                                      menuMaxHeight: 300,
                                       isExpanded: true,
                                  value: _selectedParentCategory,
                                     hint: const Text(
                                     "Parent Category",
                                      style: TextStyle(fontSize: 14),
                                          ),
                                  items: stateisLoadBankList
                                   ? state.categoryListModel.map((e) {
                                return DropdownMenuItem<String>(
                                    value: e.text,
                            child: Row(
                                  children: [
                                    Text(
                                      e.text,
                                      style: const TextStyle(
                                       fontSize: 14.0, color: 
                                      IposColors.black),
                                        ),
                                    ],
                                ));
                         }).toList()
                        : _parentBank.map((String value) {
                        return DropdownMenuItem<String>(
                                value: value,
                                child: Row(
                                  children: [
                                     Text(
                                        value,
                                        style: const TextStyle(
                                         fontSize: 14.0, color: 
                                          IposColors.black),
                                          ),
                                      ],
                                ));
                            }).toList(),

                            onChanged: (value) {
                                  setState(() {
                                    print(value);
                                    _selectedBankCategory = value;
                                  });
                              },
                              style: const TextStyle(fontSize: 30),
                                   ),
                                 ),
                                ),
                              );
                            },
                          );
                        return Container(
                               width: MediaQuery.of(context).size.width,
                               height: MediaQuery.of(context).size.height / 16.4,
                               decoration: BoxDecoration(
                                      color: Colors.white,
                                       borderRadius: BorderRadius.circular(10),
                                       border: Border.all(
                                       color: Colors.grey,
                               ),
                             ),
                         child: businessBankDropDown);
                           }
                       }

This was my Solution.

Thank you for taking the time to go through this.

I hope you have learned to use this awesome widget and this helps you resolve your bugs 🐞πŸͺ² issues...

If you would like to discuss this or any related issue chat Me. Follow me on Twitter for More...

Β