Related
I am developing a mobile application with Flutter. I am preparing a registration page for the application. On the registration page, I want to get the city and county where the user lives. I put two DropdownButtonForm of this.
After the user selects the city in the first DropdownButtonForm, the second DropdownButtonForm will have county options. I was able to do this with this code:
List<DropdownMenuItem<String>> kahramanmarasDistricts = [
const DropdownMenuItem(
value: "Onikişubat",
child: Text("Onikişubat"),
),
const DropdownMenuItem(
value: "Dulkadiroğlu",
child: Text("Dulkadiroğlu"),
),
const DropdownMenuItem(
value: "Elbistan",
child: Text("Elbistan"),
),
const DropdownMenuItem(
value: "Afşin",
child: Text("Afşin"),
),
const DropdownMenuItem(
value: "Türkoğlu",
child: Text("Türkoğlu"),
),
const DropdownMenuItem(
value: "Pazarcık",
child: Text("Pazarcık"),
),
const DropdownMenuItem(
value: "Göksun",
child: Text("Göksun"),
),
const DropdownMenuItem(
value: "Andırın",
child: Text("Andırın"),
),
const DropdownMenuItem(
value: "Çağlayancerit",
child: Text("Çağlayancerit"),
),
const DropdownMenuItem(
value: "Nurhak",
child: Text("Nurhak"),
),
const DropdownMenuItem(
value: "Ekinözü",
child: Text("Ekinözü"),
),
];
List<DropdownMenuItem<String>> diyarbakirDistricts = [
const DropdownMenuItem(
value: "Bağlar",
child: Text("Bağlar"),
),
const DropdownMenuItem(
value: "Bismil",
child: Text("Bismil"),
),
const DropdownMenuItem(
value: "Çermik",
child: Text("Çermik"),
),
const DropdownMenuItem(
value: "Çınar",
child: Text("Çınar"),
),
const DropdownMenuItem(
value: "Çüngüş",
child: Text("Çüngüş"),
),
const DropdownMenuItem(
value: "Dicle",
child: Text("Dicle"),
),
const DropdownMenuItem(
value: "Egir",
child: Text("Eğir"),
),
const DropdownMenuItem(
value: "Ergani",
child: Text("Ergani"),
),
const DropdownMenuItem(
value: "Hani",
child: Text("Hani"),
),
const DropdownMenuItem(
value: "Hazro",
child: Text("Hazro"),
),
const DropdownMenuItem(
value: "Kayapınar",
child: Text("Kayapınar"),
),
const DropdownMenuItem(
value: "Hocaköy",
child: Text("Hocaköy"),
),
const DropdownMenuItem(
value: "Kulp",
child: Text("Kulp"),
),
const DropdownMenuItem(
value: "Lice",
child: Text("Lice"),
),
const DropdownMenuItem(
value: "Silvan",
child: Text("Silvan"),
),
const DropdownMenuItem(
value: "Sur",
child: Text("Sur"),
),
const DropdownMenuItem(
value: "Yenişehir",
child: Text("Yenişehir"),
),
];
List<DropdownMenuItem<String>> citys = [
const DropdownMenuItem(
value: "Kahramanmaraş",
child: Text("Kahramanmaraş"),
),
const DropdownMenuItem(
value: "Diyarbakır",
child: Text("Diyarbakır"),
),
];
// ...
SelectCityDropDownField(),
SelectDistrictDropDownField(),
Widget SelectCityDropDownField() {
return Theme(
data: Theme.of(context).copyWith(
colorScheme: ThemeData().colorScheme.copyWith(
primary: Colors.red,
),
),
child: DropdownButtonFormField(
decoration: InputDecoration(
prefixIcon: const Icon(
Icons.location_city,
color: Color(0xFFCB3126),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(50),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(50),
borderSide: const BorderSide(
color: Color(0xFFCB3126),
),
),
),
items: citys
.map(
(e) => DropdownMenuItem<String>(
value: e.value,
child: e.child,
),
)
.toList(),
onChanged: (value) {
setState(() {
selectedCity = value.toString();
});
},
),
);
}
Widget SelectDistrictDropDownField() {
return Theme(
data: Theme.of(context).copyWith(
colorScheme: ThemeData().colorScheme.copyWith(
primary: Colors.red,
),
),
child: DropdownButtonFormField(
decoration: InputDecoration(
prefixIcon: const Icon(
Icons.location_city,
color: Color(0xFFCB3126),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(50),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(50),
borderSide: const BorderSide(
color: Color(0xFFCB3126),
),
),
),
items: districtsItem(),
onChanged: (value) {
setState(() {
selectedDistrict = value.toString();
});
},
),
);
}
districtsItem() {
switch (selectedCity) {
case "Kahramanmaraş":
return kahramanmarasDistricts;
case "Diyarbakır":
return diyarbakirDistricts;
}
}
I'm having a problem with something. The problem is this: For example, let's choose the province of Kahramanmaraş and choose Elbistan as the district. Then when I change the city to Diyarbakır, it gives an error. In other words, when I choose a different province after choosing the district, I get an error. This is error;
The following assertion was thrown building Builder(dirty, dependencies: [_FocusMarker]):
There should be exactly one item with [DropdownButtonFormField]'s value: Çermik.
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value
'package:flutter/src/material/dropdown.dart':
Failed assertion: line 939 pos 15: 'items == null || items.isEmpty || value == null ||
items.where((DropdownMenuItem<T> item) {
return item.value == value;
}).length == 1'
How can I solve this problem? Thanks in advance for your help.
It is because your districts' lists conflict when rendering.
You have to set key property to distinguish them.
child: DropdownButtonFormField(
key: selectedCity == 'Kahramanmaraş'
? const Key('Kahramanmaraş')
: const Key('Diyarbakır'),
...
You could learn more about key from below youtube link.
https://www.youtube.com/watch?v=kn0EOS-ZiIc&t=1s
I am using DropdownButton and I am facing the following error. When opening the DropdownMenuItem list, I do not have an indent from the button itself. That is, I need to get the padding between the button (DropdownButton) and the dropdown list (DropdownMenuItem) so that there is a distance. But so far I haven't been able to do it. How can you make an indent between them?
code
#override
Widget build(BuildContext context) {
return SizedBox(
width: widget.width,
child: DropdownButtonHideUnderline(
child: DropdownButton2(
items: List.generate(
widget.items.length,
(index) => DropdownMenuItem<String>(
value: widget.items[index],
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Colors.white.withOpacity(0.1),
width: 1,
),
),
),
child: StatefulBuilder(
builder: (context, setStateSB) => GFCheckboxListTile(
value: _selectedTitles.contains(widget.items[index]),
onChanged: (bool selected) {
_onItemSelect(selected, index);
setStateSB(() {});
},
selected: selected,
title: Text(
widget.items[index],
style: constants.Styles.smallTextStyleWhite,
),
padding: const EdgeInsets.only(top: 12, bottom: 13),
margin: const EdgeInsets.only(right: 0, left: 0),
size: 22,
activeBgColor: constants.Colors.greyCheckbox,
activeBorderColor: constants.Colors.greyXMiddle,
inactiveBgColor: constants.Colors.greyCheckbox,
activeIcon: SvgPicture.asset(constants.Assets.checkboxIcon),
inactiveBorderColor: constants.Colors.greyXMiddle,
type: type,
),
),
),
),
),
hint: _selectedTitles.length > 1
? const Text('Selecte EV',
style: constants.Styles.bigBookTextStyleWhite)
: Text(_selectedTitles.join().toString(),
style: constants.Styles.bigBookTextStyleWhite),
value: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value as String;
});
},
icon: SvgPicture.asset(constants.Assets.arrowDropdown),
iconSize: 21,
buttonHeight: 27,
itemHeight: 47,
dropdownMaxHeight: 185,
dropdownWidth: 140,
dropdownDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: constants.Colors.purpleMain,
),
color: constants.Colors.greyDark),
selectedItemBuilder: (context) {
return widget.items.map(
(item) {
return Row(
children: [
widget.icon ?? const SizedBox(),
const SizedBox(width: 8),
Text(
item,
style: constants.Styles.bigBookTextStyleWhite,
),
],
);
},
).toList();
},
),
),
);
}
}
In the dropdown_button2 documentation, there is a property for moving the dropdown menu Offset. You can see it here https://pub.dev/documentation/dropdown_button2/latest/dropdown_button2/DropdownButton2/offset.html
On that property you just need to set an Offset, which is composed of an X and Y values.
In your case it would look something like this:
DropdownButton2(
offset: Offset(0,10),
...
),
DropdownButton(
hint: Text('Select Priority Level', style: GoogleFonts.dosis() ,),
dropdownColor: Colors.blueGrey,
value: selectedValue,
onChanged: (newValue){
setState(() {
selectedValue = newValue;
priority = selectedValue;
});
},
items: listPriority.map((valueItem){
return DropdownMenuItem<String>(
value: valueItem,
child: Text(valueItem),
);
}).toList(),
)
The value selected is stored however when I select an item it does not show in the drop-down field. How can I fix this?
Here is sample code i did
initialize variable
int _selectedjobcategory;
Code
Flexible(
flex: 0,
child: Padding(
padding: EdgeInsets.only(left: 10, right: 10, top: 15),
child: Container(
width: double.infinity,
height: 60,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5),
border: Border.all(color: Colors.blueGrey)),
child: DropdownButtonFormField(
isExpanded: true,
itemHeight: 50,
icon: Icon(Icons.arrow_drop_down),
iconSize: 40,
// underline: SizedBox(),
hint: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Select Enquiry Type",
style: TextStyle(fontSize: 15, color: Colors.black),
),
),
value: _selectedjobcategory,
onChanged: (newValues) {
setState(() {
_selectedjobcategory = newValues;
});
},
items: jobcategory.map((jobs) {
return DropdownMenuItem(
child: Padding(
padding: const EdgeInsets.all(8.0),
child:
Text(jobs.name, style: TextStyle(fontSize: 15)),
),
value: jobs.id,
);
}).toList(),
),
),
),
),
here's a custom class of dropdown you can call it anywhere
import 'package:flutter/material.dart';
// ignore: must_be_immutable
class DropDownClass extends StatelessWidget {
var _hint;
var _val;
List _list = new List();
bool _border;
Color _underLineColor, _dropDownColor;
List get list => _list;
dynamic Function(dynamic) _listener;
DropDownClass({List list,
var hint,
Color underLineColor,
Color dropDownColor,
Color textColor,
double fontSize,
bool icon,
var val,
int type,
bool border = true,
dynamic Function(dynamic) listener,})
: _list = list,
_hint = hint,
_underLineColor = underLineColor,
_dropDownColor = dropDownColor,
_val = val,
_border = border,
_listener = listener;
#override
Widget build(BuildContext context) {
return DropdownButtonHideUnderline(
child: DropdownButtonFormField<String>(
value: _val,
dropdownColor: _dropDownColor ?? Colors.white,
decoration:_border == true? InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: _underLineColor ?? Theme
.of(context)
.hintColor,
width: 1.0,
),
)
):InputDecoration(
border: InputBorder.none,
fillColor: Colors.grey[400],
filled: true),
isExpanded: true,
hint: Text(_hint),
items: list.map((item) {
return DropdownMenuItem<String>(
value: item,
child: new Text(item,),
);
}).toList(),
onChanged: (value) {
_val = value;
if (_listener != null) _listener.call(value);
// return val;
},
),
);
}
}
in my code Container(height: 1, color: UtilColors.grey), not giving expeceted output
Container(
margin: EdgeInsets.only(left: 52, right: 48),
child: DropdownButton<String>(
isExpanded: true,
//Container(height: 1, color: UtilColors.grey),
value: _selectedUser,
items: _userTypes.map((String value) {
return new DropdownMenuItem<String>(value: value, child: new Text(value));
}).toList(),
/* decoration: InputDecoration(contentPadding: EdgeInsets.only(left: 15), suffixIcon: IconButton(onPressed: () {
// _userTypes.map((String value){return new DropdownMenuItem<String>(value: value, child: new Text(value));}).toList();
}, icon: Icon(null),)),*/
icon: Icon(Icons.keyboard_arrow_down),
hint: Text(UtilString.userType),
onChanged: (value) => setState(() => _selectedUser = value),
),
),
finally got the solution with DropdownButton -
underline: Container( height: 2,
color: Colors.deepPurpleAccent,),
this will change dropdown underline color.
I've one drop down and there some value inside the drop-down button and I need to by default selected value. you can seel below piece of snippet where you can find the drop-down value. I need it always there is by default selected value Normal. hope you understand the question.
FormBuilder(
autovalidate: autovalidate,
child: FormBuilderCustomField(
attribute: "Select Address",
validators: [
FormBuilderValidators.required(),
],
formField: FormField(
builder: (FormFieldState<dynamic> field) {
return InputDecorator(
decoration: InputDecoration(
errorText: field.errorText,
filled: false,
isDense: true,
border: InputBorder.none,
icon: Container(
width: 50.0,
height: 50.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
color: colorStyles['primary_light'],
),
child: Icon(
Icons.business_center,
color: colorStyles['primary'],
),
),
),
isEmpty: _typeValue == [],
child: new DropdownButtonHideUnderline(
child: DropdownButton(
hint: Text("Service Type"),
isExpanded: true,
items: [
"normal",
"urgent",
"emergency",
].map((option) {
return DropdownMenuItem(
child: Text("$option"),
value: option,
);
}).toList(),
value: field.value,
onChanged: (value) {
field.didChange(value);
_serviceType = value;
},
),
),
);
},
)),
);
Just Asign on initState()
selectedDropDownValue = "normal";
In DropDown, asign selectedDropDownValue to value, and update on onChanged callback
new DropdownButtonHideUnderline(
child: DropdownButton(
hint: Text("Service Type"),
isExpanded: true,
items: [
"normal",
"urgent",
"emergency",
].map((option) {
return DropdownMenuItem(
child: Text("$option"),
value: option,
);
}).toList(),
value: selectedDropDownValue, //asign the selected value
onChanged: (value) {
setState((){
selectedDropDownValue = value; //on selection, selectedDropDownValue i sUpdated
});
},
),
),
);