How to implement drop down list in flutter?
Try this
DropdownButton<String>(
items: <String>['A', 'B', 'C', 'D'].map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (_) {},
)
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:
Open dropdown and select value:
Reflect selected value to dropdown:
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 eliminatesitems == null
. - Non-empty list was provided. This eliminates
items.isEmpty
. - A value (
_selectedLocation
) was also given. This eliminatesvalue == null
. Note that this isDropdownButton
's value, notDropdownMenuItem
's value.
Hence only the last check is left. It boils down to something like:
Iterate through
DropdownMenuItem
's. Find all that have avalue
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-selectPlease choose a location
option. - Option 2. Pass something to
hint:
paremter and setselectedLocation
tonull
(to satisfyvalue == null
condition). Useful if you don't wantPlease 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(),
),
),
),
);
}
}