150

I have a list of locations that i want to implement as a dropdown list in Flutter. Im pretty new to the language. Here's what i have done.

new DropdownButton(
  value: _selectedLocation,
  onChanged: (String newValue) {
    setState(() {
      _selectedLocation = newValue;
     });
},
items: _locations.map((String location) {
  return new DropdownMenuItem<String>(
     child: new Text(location),
  );
}).toList(),

This is my list of items:

List<String> _locations = ['A', 'B', 'C', 'D'];

And I am getting the following error.

Another exception was thrown: 'package:flutter/src/material/dropdown.dart': Failed assertion: line 468 pos 15: 'value == null || items.where((DropdownMenuItem<T> item) => item.value == value).length == 1': is not true.

I assume the value of _selectedLocation is getting null. But i am initialising it like so.

String _selectedLocation = 'Please choose a location';

Chaythanya Nair
  • 4,774
  • 6
  • 32
  • 40
  • 1
    The problem is that String _selectedLocation = 'Please choose a location'; is not in the DropdownMenuItem values. What you are trying to do is Hint probably. – MSquare Apr 29 '20 at 21:53
  • This site helped me https://codesinsider.com/flutter-dropdown-button-example/ – ikmazameti Oct 20 '21 at 10:28

23 Answers23

286

Try this

DropdownButton<String>(
  items: <String>['A', 'B', 'C', 'D'].map((String value) {
    return DropdownMenuItem<String>(
      value: value,
      child: Text(value),
    );
  }).toList(),
  onChanged: (_) {},
)
    
WSBT
  • 33,033
  • 18
  • 128
  • 133
Pravin Raj
  • 3,439
  • 1
  • 13
  • 13
  • Tried adding `value : value` in `DropdownMenuItem`. Still getting the same error. Guess some error with `value : _selectedLocation` in the DropDownButton. – Chaythanya Nair Mar 15 '18 at 03:56
  • 1
    Great thanks to @Pravin Raj. you arrow to me think about the type of returned List by forcing the `DropdownMenuItem` – Ruberandinda Patience May 30 '20 at 10:19
  • DropDown width crosses screen width when item text s so large Eg:['sdfdfsd fas dgshdfgasduf vasydf asyda sd f asdf s df sdgf sd fsdg fhs gdfhds', 'fhsfsdhfjs dfsdkf sdf ssdf sdfs dfhjs dhfb fd ']. Help me out @Pravin – Kudos Mar 19 '21 at 10:21
  • Use text wrapping @Kudos : https://stackoverflow.com/questions/51930754/flutter-wrapping-text – funder7 Apr 19 '21 at 09:10
  • it dont work when wrapped inside container ? – appdev May 12 '22 at 06:27
101

For the solution, scroll to the end of the answer.

First of all, let's investigate what the error says (I have cited the error that's thrown with Flutter 1.2, but the idea is the same):

Failed assertion: line 560 pos 15: 'items == null || items.isEmpty || value == null || items.where((DropdownMenuItem item) => item.value == value).length == 1': is not true.

There are four or conditions. At least one of them must be fulfilled:

  • Items (a list of DropdownMenuItem widgets) were provided. This eliminates items == null.
  • Non-empty list was provided. This eliminates items.isEmpty.
  • A value (_selectedLocation) was also given. This eliminates value == null. Note that this is DropdownButton's value, not DropdownMenuItem's value.

Hence only the last check is left. It boils down to something like:

Iterate through DropdownMenuItem's. Find all that have a value that's equal to _selectedLocation. Then, check how many items matching it were found. There must be exactly one widget that has this value. Otherwise, throw an error.

The way code is presented, there is not a DropdownMenuItem widget that has a value of _selectedLocation. Instead, all the widgets have their value set to null. Since null != _selectedLocation, last condition fails. Verify this by setting _selectedLocation to null - the app should run.

To fix the issue, we first need to set a value on each DropdownMenuItem (so that something could be passed to onChanged callback):

return DropdownMenuItem(
    child: new Text(location),
    value: location,
);

The app will still fail. This is because your list still does not contain _selectedLocation's value. You can make the app work in two ways:

  • Option 1. Add another widget that has the value (to satisfy items.where((DropdownMenuItem<T> item) => item.value == value).length == 1). Might be useful if you want to let the user re-select Please choose a location option.
  • Option 2. Pass something to hint: paremter and set selectedLocation to null (to satisfy value == null condition). Useful if you don't want Please choose a location to remain an option.

See the code below that shows how to do it:

import 'package:flutter/material.dart';

void main() {
  runApp(Example());
}

class Example extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
//  List<String> _locations = ['Please choose a location', 'A', 'B', 'C', 'D']; // Option 1
//  String _selectedLocation = 'Please choose a location'; // Option 1
  List<String> _locations = ['A', 'B', 'C', 'D']; // Option 2
  String _selectedLocation; // Option 2

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: DropdownButton(
            hint: Text('Please choose a location'), // Not necessary for Option 1
            value: _selectedLocation,
            onChanged: (newValue) {
              setState(() {
                _selectedLocation = newValue;
              });
            },
            items: _locations.map((location) {
              return DropdownMenuItem(
                child: new Text(location),
                value: location,
              );
            }).toList(),
          ),
        ),
      ),
    );
  }
}
cegas
  • 2,823
  • 3
  • 16
  • 16
29

Use StatefulWidget and setState to update dropdown.

  String _dropDownValue;

  @override
  Widget build(BuildContext context) {
    return DropdownButton(
      hint: _dropDownValue == null
          ? Text('Dropdown')
          : Text(
              _dropDownValue,
              style: TextStyle(color: Colors.blue),
            ),
      isExpanded: true,
      iconSize: 30.0,
      style: TextStyle(color: Colors.blue),
      items: ['One', 'Two', 'Three'].map(
        (val) {
          return DropdownMenuItem<String>(
            value: val,
            child: Text(val),
          );
        },
      ).toList(),
      onChanged: (val) {
        setState(
          () {
            _dropDownValue = val;
          },
        );
      },
    );
  }

initial state of dropdown:

Initial State

Open dropdown and select value:

Select Value

Reflect selected value to dropdown:

Value selected

Mizuki
  • 2,153
  • 1
  • 17
  • 29
23

If you don't want the Drop list to show up like a popup. You can customize it this way just like me (it will show up as if on the same flat, see image below):

enter image description here

After expand:

enter image description here

Please follow the steps below: First, create a dart file named drop_list_model.dart:

import 'package:flutter/material.dart';

class DropListModel {
  DropListModel(this.listOptionItems);

  final List<OptionItem> listOptionItems;
}

class OptionItem {
  final String id;
  final String title;

  OptionItem({@required this.id, @required this.title});
}

Next, create file file select_drop_list.dart:

import 'package:flutter/material.dart';
import 'package:time_keeping/model/drop_list_model.dart';
import 'package:time_keeping/widgets/src/core_internal.dart';

class SelectDropList extends StatefulWidget {
  final OptionItem itemSelected;
  final DropListModel dropListModel;
  final Function(OptionItem optionItem) onOptionSelected;

  SelectDropList(this.itemSelected, this.dropListModel, this.onOptionSelected);

  @override
  _SelectDropListState createState() => _SelectDropListState(itemSelected, dropListModel);
}

class _SelectDropListState extends State<SelectDropList> with SingleTickerProviderStateMixin {

  OptionItem optionItemSelected;
  final DropListModel dropListModel;

  AnimationController expandController;
  Animation<double> animation;

  bool isShow = false;

  _SelectDropListState(this.optionItemSelected, this.dropListModel);

  @override
  void initState() {
    super.initState();
    expandController = AnimationController(
        vsync: this,
        duration: Duration(milliseconds: 350)
    );
    animation = CurvedAnimation(
      parent: expandController,
      curve: Curves.fastOutSlowIn,
    );
    _runExpandCheck();
  }

  void _runExpandCheck() {
    if(isShow) {
      expandController.forward();
    } else {
      expandController.reverse();
    }
  }

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

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: <Widget>[
          Container(
            padding: const EdgeInsets.symmetric(
                horizontal: 15, vertical: 17),
            decoration: new BoxDecoration(
              borderRadius: BorderRadius.circular(20.0),
              color: Colors.white,
              boxShadow: [
                BoxShadow(
                    blurRadius: 10,
                    color: Colors.black26,
                    offset: Offset(0, 2))
              ],
            ),
            child: new Row(
              mainAxisSize: MainAxisSize.max,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                Icon(Icons.card_travel, color: Color(0xFF307DF1),),
                SizedBox(width: 10,),
                Expanded(
                    child: GestureDetector(
                      onTap: () {
                        this.isShow = !this.isShow;
                        _runExpandCheck();
                        setState(() {

                        });
                      },
                      child: Text(optionItemSelected.title, style: TextStyle(
                          color: Color(0xFF307DF1),
                          fontSize: 16),),
                    )
                ),
                Align(
                  alignment: Alignment(1, 0),
                  child: Icon(
                    isShow ? Icons.arrow_drop_down : Icons.arrow_right,
                    color: Color(0xFF307DF1),
                    size: 15,
                  ),
                ),
              ],
            ),
          ),
          SizeTransition(
              axisAlignment: 1.0,
              sizeFactor: animation,
              child: Container(
                margin: const EdgeInsets.only(bottom: 10),
                  padding: const EdgeInsets.only(bottom: 10),
                  decoration: new BoxDecoration(
                    borderRadius: BorderRadius.only(bottomLeft: Radius.circular(20), bottomRight: Radius.circular(20)),
                    color: Colors.white,
                    boxShadow: [
                      BoxShadow(
                          blurRadius: 4,
                          color: Colors.black26,
                          offset: Offset(0, 4))
                    ],
                  ),
                  child: _buildDropListOptions(dropListModel.listOptionItems, context)
              )
          ),
//          Divider(color: Colors.grey.shade300, height: 1,)
        ],
      ),
    );
  }

  Column _buildDropListOptions(List<OptionItem> items, BuildContext context) {
    return Column(
      children: items.map((item) => _buildSubMenu(item, context)).toList(),
    );
  }

  Widget _buildSubMenu(OptionItem item, BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(left: 26.0, top: 5, bottom: 5),
      child: GestureDetector(
        child: Row(
          children: <Widget>[
            Expanded(
              flex: 1,
              child: Container(
                padding: const EdgeInsets.only(top: 20),
                decoration: BoxDecoration(
                  border: Border(top: BorderSide(color: Colors.grey[200], width: 1)),
                ),
                child: Text(item.title,
                    style: TextStyle(
                        color: Color(0xFF307DF1),
                        fontWeight: FontWeight.w400,
                        fontSize: 14),
                    maxLines: 3,
                    textAlign: TextAlign.start,
                    overflow: TextOverflow.ellipsis),
              ),
            ),
          ],
        ),
        onTap: () {
          this.optionItemSelected = item;
          isShow = false;
          expandController.reverse();
          widget.onOptionSelected(item);
        },
      ),
    );
  }

}

Initialize value:

DropListModel dropListModel = DropListModel([OptionItem(id: "1", title: "Option 1"), OptionItem(id: "2", title: "Option 2")]);
OptionItem optionItemSelected = OptionItem(id: null, title: "Chọn quyền truy cập");

Finally use it:

SelectDropList(
           this.optionItemSelected, 
           this.dropListModel, 
           (optionItem){
                 optionItemSelected = optionItem;
                    setState(() {
  
                    });
               },
            )
Doan Bui
  • 3,572
  • 25
  • 36
17

you have to take this into account (from DropdownButton docs):

"The items must have distinct values and if value isn't null it must be among them."

So basically you have this list of strings

List<String> _locations = ['A', 'B', 'C', 'D'];

And your value in Dropdown value property is initialised like this:

String _selectedLocation = 'Please choose a location';

Just try with this list:

List<String> _locations = ['Please choose a location', 'A', 'B', 'C', 'D'];

That should work :)

Also check out the "hint" property if you don't want to add a String like that (out of the list context), you could go with something like this:

DropdownButton<int>(
          items: locations.map((String val) {
                   return new DropdownMenuItem<String>(
                        value: val,
                        child: new Text(val),
                         );
                    }).toList(),
          hint: Text("Please choose a location"),
          onChanged: (newVal) {
                  _selectedLocation = newVal;
                  this.setState(() {});
                  });
Rubs
  • 809
  • 9
  • 21
11

For anyone interested to implement a DropDown of custom class you can follow the bellow steps.

  1. Suppose you have a class called Language with the following code and a static method which returns a List<Language>

    class Language {
      final int id;
      final String name;
      final String languageCode;
    
      const Language(this.id, this.name, this.languageCode);
    
    
    }
    
     const List<Language> getLanguages = <Language>[
            Language(1, 'English', 'en'),
            Language(2, 'فارسی', 'fa'),
            Language(3, 'پشتو', 'ps'),
         ];
    
  2. Anywhere you want to implement a DropDown you can import the Language class first use it as follow

        DropdownButton(
            underline: SizedBox(),
            icon: Icon(
                        Icons.language,
                        color: Colors.white,
                        ),
            items: getLanguages.map((Language lang) {
            return new DropdownMenuItem<String>(
                            value: lang.languageCode,
                            child: new Text(lang.name),
                          );
                        }).toList(),
    
            onChanged: (val) {
                          print(val);
                       },
          )
    
Seddiq Sorush
  • 2,709
  • 2
  • 20
  • 20
  • 1
    There should be exactly one item with [DropdownButton]'s value: Instance of 'Relationship'. Either zero or 2 or more [DropdownMenuItem]s were detected with the same value 'package:flutter/src/material/dropdown.dart': Failed assertion: line 834 pos 15: 'items == null || items.isEmpty || value == null || items.where((DropdownMenuItem item) { return item.value == value; }).length == 1' – Tarun Sharma Nov 27 '20 at 12:34
  • Getting this after rebuild call. – Tarun Sharma Nov 27 '20 at 12:34
  • 2
    Hi dear, this means that you have implemented `DropdownButton` successfully. But, somehow the program is trying to put duplicate values in the Dropdown. So, kindly make sure about the state changes. I have edited the code and made the list as `const`. kindly try it and see if it solves your issue. – Seddiq Sorush Nov 27 '20 at 18:13
8

You need to add value: location in your code to work it. Check this out.

items: _locations.map((String location) {
  return new DropdownMenuItem<String>(
     child: new Text(location),
     value: location,
  );
}).toList(),
DwlRathod
  • 750
  • 6
  • 17
7

place the value inside the items.then it will work,

new DropdownButton<String>(
              items:_dropitems.map((String val){
                return DropdownMenuItem<String>(
                  value: val,
                  child: new Text(val),
                );
              }).toList(),
              hint:Text(_SelectdType),
              onChanged:(String val){
                _SelectdType= val;
                setState(() {});
                })
Ajit Paul
  • 199
  • 3
  • 3
  • And if you use a custom object(DropdownButton) and it still doesn't work, just remember to override the == operator and the hashCode getter for your custom object. – Jørgen Andersen Sep 09 '19 at 05:19
6

You can use DropDownButton class in order to create drop down list :

...
...
String dropdownValue = 'One';
...
...
Widget build(BuildContext context) {
return Scaffold(
  body: Center(
    child: DropdownButton<String>(
      value: dropdownValue,
      onChanged: (String newValue) {
        setState(() {
          dropdownValue = newValue;
        });
      },
      items: <String>['One', 'Two', 'Free', 'Four']
          .map<DropdownMenuItem<String>>((String value) {
        return DropdownMenuItem<String>(
          value: value,
          child: Text(value),
        );
      }).toList(),
    ),
  ),
);
...
...

please refer to this flutter documentation

utarid
  • 1,642
  • 4
  • 24
  • 38
4

Let say we are creating a drop down list of currency:

List _currency = ["INR", "USD", "SGD", "EUR", "PND"];
List<DropdownMenuItem<String>> _dropDownMenuCurrencyItems;
String _currentCurrency;

List<DropdownMenuItem<String>> getDropDownMenuCurrencyItems() {
  List<DropdownMenuItem<String>> items = new List();
  for (String currency in _currency) {
    items.add(
      new DropdownMenuItem(value: currency, child: new Text(currency)));
  }
  return items;
}

void changedDropDownItem(String selectedCurrency) {
  setState(() {
    _currentCurrency = selectedCurrency;
  });
}

Add below code in body part:

new Row(children: <Widget>[
  new Text("Currency: "),
  new Container(
    padding: new EdgeInsets.all(16.0),
  ),
  new DropdownButton(
    value: _currentCurrency,
    items: _dropDownMenuCurrencyItems,
    onChanged: changedDropDownItem,
  )
])
joce
  • 9,624
  • 19
  • 56
  • 74
lavish
  • 96
  • 5
4

Make your custom Widget:

import 'package:flutter/material.dart';

/// Usage:
/// CustomDropdown<String>(
//     items: ['A', 'B', 'C'],
//     onChanged: (val) => _selectedValue = val,
//     center: true,
//  ),
/// --> Remember: f.toString() at line 105 is @override String toString() in your class
// @override
// String toString() {
//   return name;
// }
class CustomDropdown<T> extends StatefulWidget {
  CustomDropdown({
    Key key,
    @required this.items,
    @required this.onChanged,
    this.onInit,
    this.padding = const EdgeInsets.only(top: 10.0),
    this.height = 40,
    this.center = false,
    this.itemText,
  }) : super(key: key);

  /// list item
  List<T> items;

  /// onChanged
  void Function(T value) onChanged;

  /// onInit
  void Function(T value) onInit;

  ///padding
  EdgeInsetsGeometry padding;

  /// container height
  double height;

  /// center
  bool center;

  String Function(String text) itemText;

  @override
  _CustomDropdownState<T> createState() => _CustomDropdownState();
}

class _CustomDropdownState<T> extends State<CustomDropdown<T>> {
  /// current selected value
  T _selectedValue;

  @override
  void initState() {
    super.initState();
    _initValue();
  }

  @override
  Widget build(BuildContext context) {
    return _buildBody();
  }

  /// set default selected value when init
  _initValue() {
    _selectedValue = widget.items[0];
    if (widget.onInit != null) widget.onInit(_selectedValue);
  }

  _buildBody() {
    Color borderLine = Color(0xffc0c0c0);
    return Padding(
      padding: widget.padding,
      child: Row(
        mainAxisAlignment: (widget.center)
            ? MainAxisAlignment.center
            : MainAxisAlignment.start,
        children: <Widget>[
          new Container(
            height: widget.height,
            padding: EdgeInsets.only(left: 10.0),
            decoration: ShapeDecoration(
              color: Colors.white,
              shape: RoundedRectangleBorder(
                side: BorderSide(
                    width: 0.8, style: BorderStyle.solid, color: borderLine),
                borderRadius: BorderRadius.all(Radius.circular(5.0)),
              ),
            ),
            child: new DropdownButtonHideUnderline(
              child: new DropdownButton<T>(
                value: _selectedValue,
                onChanged: (T newValue) {
                  setState(() {
                    _selectedValue = newValue;
                    widget.onChanged(newValue);
                  });
                },
                items: widget.items.map((T f) {
                  return new DropdownMenuItem<T>(
                    value: f,
                    child: new Text(
                      (widget.itemText != null)
                          ? widget.itemText(f.toString())
                          : f.toString(),
                      style: new TextStyle(color: Colors.black),
                    ),
                  );
                }).toList(),
              ),
            ),
          ),
        ],
      ),
    );
  }
}
  • After that, simple call:

    CustomDropdown<String>(
          items: ['A', 'B', 'C'],
          onChanged: (val) => _selectedValue = val,
          center: true,
        )
    
  • Or with your class:

    class Student { int id; String name;

    A(this.id,this.name);

    //remember override @override String toString() { return name; } }

And call:

CustomDropdown<Student>(
    items: studentList,
    onChanged: (val) => _selectedValue = val,
    center: true,
),
O Thạnh Ldt
  • 1,103
  • 10
  • 11
3

Change

List<String> _locations = ['A', 'B', 'C', 'D'];

To

List<String> _locations = [_selectedLocation, 'A', 'B', 'C', 'D'];

_selectedLocation needs to be part of your item List;

sammyni
  • 29
  • 1
3

This one has the hint text that shows up before selection

DropdownButton<String>(
      focusColor: Colors.white,
      value: _chosenValue,
      //elevation: 5,
      style: TextStyle(color: Colors.white),
      iconEnabledColor: Colors.black,
      items:classes.map<DropdownMenuItem<String>>((String value) {
        return DropdownMenuItem<String>(
          value: value,
          child: Text(
            value,
            style: TextStyle(color: Colors.black),
          ),
        );
      }).toList(),
      hint: Text(
        "All Classes",
        style: TextStyle(
            color: Colors.black, fontSize: 14, fontWeight: FontWeight.w500),
      ),
      onChanged: (String value) {
        setState(() {
          _chosenValue = value;
        });
      },
    );
MSaudi
  • 4,442
  • 2
  • 40
  • 65
2

This is the code which I found most useful. It gives you everything you need. (ctrl+c , ctrl+v will work)

  List<String> location = ['One', 'Two', 'Three', 'Four'];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Fuel Entry')),
      body: Padding(
        padding: const EdgeInsets.all(15.0),
        child: Center(
          child: Column(
            children: [
              DropdownButton<String>(
                hint: Text('Select a vehicle '),
                value: dropdownValue,
                icon: const Icon(Icons.arrow_downward),
                iconSize: 24,
                elevation: 16,
                onChanged: (String? newValue) {
                  setState(() {
                    dropdownValue = newValue!;
                  });
                },
                items: location.map<DropdownMenuItem<String>>((String value) {
                  return DropdownMenuItem<String>(
                    value: value,
                    child: Text(value),
                  );
                }).toList(),
              )
            ],
          ),
        ),
      ),
    );
mafortis
  • 6,750
  • 23
  • 130
  • 288
2
DropdownButton<int>(
                value: 6, //selected
                icon: Icon(Icons.arrow_downward),
                iconSize: 24,
                elevation: 16,
                style: TextStyle(color: Theme.of(context).accentColor),
                underline: Container(
                  height: 2,
                  color: Colors.deepPurpleAccent,
                ),
                onChanged: (int? newValue) {},
                items: <int>[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
                    .map<DropdownMenuItem<int>>((int value) {
                  return DropdownMenuItem<int>(
                    value: value,
                    child: Text(value.toString()),
                  );
                }).toList(),
              )
buckleyJohnson
  • 459
  • 4
  • 12
1

I was facing a similar issue with the DropDownButton when i was trying to display a dynamic list of strings in the dropdown. I ended up creating a plugin : flutter_search_panel. Not a dropdown plugin, but you can display the items with the search functionality.

Use the following code for using the widget :

    FlutterSearchPanel(
        padding: EdgeInsets.all(10.0),
        selected: 'a',
        title: 'Demo Search Page',
        data: ['This', 'is', 'a', 'test', 'array'],
        icon: new Icon(Icons.label, color: Colors.black),
        color: Colors.white,
        textStyle: new TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 20.0, decorationStyle: TextDecorationStyle.dotted),
        onChanged: (value) {
          print(value);
        },
   ),
dranzer
  • 31
  • 2
1

It had happened to me when I replace the default value with a new dynamic value. But, somehow your code may be dependent on that default value. So try keeping a constant with default value stored somewhere to fallback.

const defVal = 'abcd';
String dynVal = defVal;

// dropdown list whose value is dynVal that keeps changing with onchanged
// when rebuilding or setState((){})

dynVal = defVal;
// rebuilding here...
Vijay Kumar Kanta
  • 1,111
  • 1
  • 15
  • 25
0

The error you are getting is due to ask for a property of a null object. Your item must be null so when asking for its value to be compared you are getting that error. Check that you are getting data or your list is a list of objects and not simple strings.

Matias
  • 708
  • 10
  • 24
0

When I ran into this issue of wanting a less generic DropdownStringButton, I just created it:

dropdown_string_button.dart

import 'package:flutter/material.dart';
// Subclass of DropdownButton based on String only values.
// Yes, I know Flutter discourages subclassing, but this seems to be
// a reasonable exception where a commonly used specialization can be
// made more easily usable.
//
// Usage: 
// DropdownStringButton(items: ['A', 'B', 'C'], value: 'A', onChanged: (string) {})
//
class DropdownStringButton extends DropdownButton<String> {
  DropdownStringButton({
    Key key, @required List<String> items, value, hint, disabledHint,
    @required onChanged, elevation = 8, style, iconSize = 24.0, isDense = false,
    isExpanded = false, }) : 
    assert(items == null || value == null || items.where((String item) => item == value).length == 1),
        super(
          key: key,
          items: items.map((String item) {
            return DropdownMenuItem<String>(child: Text(item), value: item);
          }).toList(),
        value: value, hint: hint, disabledHint: disabledHint, onChanged: onChanged,
        elevation: elevation, style: style, iconSize: iconSize, isDense: isDense,
        isExpanded: isExpanded,
        );
    }
Cirec Beback
  • 693
  • 10
  • 16
0

Use this code.

class PlayerPreferences extends StatefulWidget {
  final int numPlayers;
  PlayerPreferences({this.numPlayers});

  @override
  _PlayerPreferencesState createState() => _PlayerPreferencesState();
}

class _PlayerPreferencesState extends State<PlayerPreferences> {
  int dropDownValue = 0;
  @override
  Widget build(BuildContext context) {
    return Container(
      child: DropdownButton(
        value: dropDownValue,
        onChanged: (int newVal){
          setState(() {
            dropDownValue = newVal;
          });
        },
        items: [
          DropdownMenuItem(
            value: 0,
            child: Text('Yellow'),
          ),
          DropdownMenuItem(
            value: 1,
            child: Text('Red'),
          ),
          DropdownMenuItem(
            value: 2,
            child: Text('Blue'),
          ),
          DropdownMenuItem(
            value: 3,
            child: Text('Green'),
          ),
        ],
      ),
    );
  }
}

and in the main body we call as

class ModeSelection extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Container(
          child: PlayerPreferences(),
        ) ,
      ),
    );
  }
}
0

it is very simple

DropdownButton<String>(
                      isExpanded: true,
                      value: selectedLocation,
                      icon: const Icon(Icons.arrow_circle_down),
                      iconSize: 20,
                      elevation: 16,
                      underline: Container(),
                      onChanged: (String newValue) {
                        setState(() {
                          selectedLocation = newValue;
                        });
                      },
                      items: List.generate(
                        _locations.length,
                        (index) => DropdownMenuItem(
                          child: Padding(
                            padding: const EdgeInsets.all(8.0),
                            child: Text(
                              _locations[index] 
                            ),
                          ),
                          value: _locations[index],
                        ),
                      ),
                    ),
    ),

Complete Code Example Given Belowenter image description here

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  
  



  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
 var _locations = ['A', 'B', 'C', 'D'];
  String selectedLocation = 'A';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        child: DropdownButton<String>(
                          isExpanded: true,
                          value: selectedLocation,
                          icon: const Icon(Icons.arrow_circle_down),
                          iconSize: 20,
                          elevation: 16,
                          underline: Container(),
                          onChanged: (String newValue) {
                            setState(() {
                              selectedLocation = newValue;
                            });
                          },
                          items: List.generate(
                            _locations.length,
                            (index) => DropdownMenuItem(
                              child: Padding(
                                padding: const EdgeInsets.all(8.0),
                                child: Text(
                                  _locations[index] 
                                ),
                              ),
                              value: _locations[index],
                            ),
                          ),
                        ),
        ),
      
    );
  }
}
Osama Buzdar
  • 1,115
  • 10
  • 20
0

You can use like this

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

@override
 State<DropDownMenu> createState() => _DropDownMenuState();
}

class _DropDownMenuState extends State<DropDownMenu> {
String? dropDownIndex;
var dropDownList = ["Delete","Change","Remove","Save"];

@override
Widget build(BuildContext context) {
return DropdownButton(
     icon: const Icon(Icons.expand_circle_down),
     dropdownColor: Colors.yellow,
     hint: const Text("select"),
     enableFeedback: true,
     iconSize: 16,
     borderRadius: BorderRadius.circular(16),
     style: const TextStyle(
      color: Colors.green,
      decoration: TextDecoration.underline,
      decorationColor: Colors.yellow,
     ),

  items: dropDownList.map((value) => DropdownMenuItem(value: value,child:  
  Text(value),)).toList(),
  onChanged: (String? index) {
      setState(() {
        dropDownIndex = index;
      });
  },
  value: dropDownIndex,
      );
    }
  }
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 08 '23 at 04:31
0
import 'package:flutter/material.dart';
import 'package:pax_pos/resource/values/app_colors.dart';
import 'package:pax_pos/utils/widget_helper.dart';

class DropdownWidget extends StatefulWidget {
 const DropdownWidget(
  {Key? key, required this.onTapItem, required this.itemList})
  : super(key: key);

  final Function onTapItem;
  final List<String> itemList;

  @override
  State<DropdownWidget> createState() => _DropdownWidgetState();
}

class _DropdownWidgetState extends State<DropdownWidget>
    with TickerProviderStateMixin {
  String header = "Day";
  final LayerLink _layerLink = LayerLink();
  late OverlayEntry _overlayEntry;
  bool _isOpen = false;

  GlobalKey keyDropdown = GlobalKey();

  //Controller Animation
  late AnimationController _animationController;
  late Animation<double> _expandAnimation;
  //late AnimationController _controller;
  late Animation<double> _iconTurns;

  static final Animatable<double> _iconTurnTween =
    Tween<double>(begin: 0.0, end: 0.5)
      .chain(CurveTween(curve: Curves.fastOutSlowIn));

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

  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(
    vsync: this,
    duration: const Duration(milliseconds: 200),
  );
  _expandAnimation = CurvedAnimation(
    parent: _animationController,
    curve: Curves.easeInOut,
  );
  _iconTurns = _animationController.drive(_iconTurnTween);
 }

 @override
 Widget build(BuildContext context) {
   return CompositedTransformTarget(
  link: _layerLink,
  child: InkWell(
    onTap: _toggleDropdown,
    child: Container(
        key: keyDropdown,
        height: 50,
        padding: const EdgeInsets.symmetric(horizontal: 15),
        decoration: BoxDecoration(
            border: Border.all(width: 1.5, color: AppColors.PRIMARY_COLOR),
            borderRadius: BorderRadius.circular(10)),
        child: Row(
          children: [
            Center(
                child: Text(
              header,
              style: const TextStyle(
                  //fontWeight: FontWeight.w600,
                  fontSize: 16,
                  color: AppColors.PRIMARY_COLOR),
            )),
            const SizedBox(
              width: 15,
            ),
            RotationTransition(
              turns: _iconTurns,
              child: const SizedBox(
                  width: 20,
                  height: 20,
                  child: Icon(
                    Icons.expand_more,
                    color: AppColors.PRIMARY_COLOR,
                  )),
            ),
          ],
        )), //Define your child here
  ),
);
}

OverlayEntry _createOverlayEntry(Size size) {
return OverlayEntry(
  builder: (context) => GestureDetector(
    onTap: () => _toggleDropdown(close: true),
    behavior: HitTestBehavior.translucent,
    // full screen container to register taps anywhere and close drop down
    child: SizedBox(
      height: MediaQuery.of(context).size.height,
      width: MediaQuery.of(context).size.width,
      child: Stack(
        children: [
          Positioned(
            left: 100,
            top: 100.0,
            width: size.width,
            child: CompositedTransformFollower(
              //use offset to control where your dropdown appears
              offset: Offset(0, size.height + 8),
              link: _layerLink,
              showWhenUnlinked: false,
              child: Material(
                elevation: 2,
                borderRadius: BorderRadius.circular(6),
                borderOnForeground: true,
                color: Colors.white,
                child: Container(
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(6),
                    boxShadow: [
                      BoxShadow(
                          color: AppColors.BACKGROUND_COLOR_FILTER_STATUS
                              .withOpacity(0.5),
                          spreadRadius: 2,
                          blurRadius: 1,
                          offset: const Offset(
                              0, 1) // changes position of shadow
                          ),
                    ],
                  ),
                  child: SizeTransition(
                    axisAlignment: 1,
                    sizeFactor: _expandAnimation,
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.start,
                      crossAxisAlignment: CrossAxisAlignment.stretch,
                      children: [
                        ...WidgetHelper.map(widget.itemList,
                            (int index, value) {
                          String title = value;
                          return Material(
                            color: Colors.transparent,
                            borderRadius: BorderRadius.circular(5),
                            child: InkWell(
                              onTap: () {
                                widget.onTapItem(title);
                                _toggleDropdown(close: true);
                              },
                              child: Container(
                                  padding: const EdgeInsets.symmetric(
                                      horizontal: 15, vertical: 10),
                                  child: Text(title)),
                            ),
                          );
                        }),
                        //These are the options that appear in the dropdown
                      ],
                    ),
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    ),
   ),
  );
 }

void _toggleDropdown({
bool close = false,
}) async {
if (_isOpen || close) {
  _animationController.reverse().then((value) {`enter code here`
    _overlayEntry.remove();
    if (mounted) {
      setState(() {
        _isOpen = false;
      });
    }
  });
} else {
  final overlayName = Overlay.of(keyDropdown.currentContext!)!;
  final renderBox =
      keyDropdown.currentContext!.findRenderObject() as RenderBox;
  final size = renderBox.size;
  _overlayEntry = _createOverlayEntry(size);
  //Overlay.of(context)!.insert(_overlayEntry);
  overlayName.insert(_overlayEntry);
  setState(() => _isOpen = true);
  _animationController.forward();
   }
 }
}
Hoang
  • 87
  • 3