Show form based on item selected in DropdownButtonFormField flutter - flutter

I am using this dropdownbuttonform to allow user to make selection from a list of items. When user select Item 1, I want to show a form for the user to enter the details. I don't know if DropdownButtonFormField is the right widget to use and how to go about it.
This is a snippet of my drop down form
List items = ['Item 1', 'Item 2' 'Item 3', 'Item 4'];
DropdownButtonFormField(
value: selectedStatus,
onChanged: ( value) {
setState(() {
selectedStatus = value.toString();
});
},
selectedItemBuilder: (context) => status.map((item) {
return DropdownMenuItem(
value: item,
child: Text(
item,
style: TextStyle(
color: Color(0xFF0E0E0E),
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
);
}).toList(),
decoration: InputDecoration(
border: InputBorder.none,
filled: true,
fillColor: Colors.white,
),
items: status.map((status) {
return DropdownMenuItem<String>(
value: status,
child: Text(
status,
style: TextStyle(
color: Colors.black,
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
);
}).toList(),
),

You can use conditional if to present the new widget. like
child: Column(
children: [
DropdownButtonFormField(..),
if (selectedStatus == items[0]) TextFormField()
Demo
List items = ['Item 1', 'Item 2', 'Item 3', 'Item 4'];
String? selectedStatus;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Form(
child: Column(
children: [
DropdownButtonFormField(
value: selectedStatus,
onChanged: (value) {
setState(() {
selectedStatus = value.toString();
});
},
items: items.map((status) {
return DropdownMenuItem<String>(
value: status,
child: Text(
status,
style: TextStyle(
color: Colors.black,
fontSize: 14,
fontWeight: FontWeight.w500,
),
),
);
}).toList(),
),
//or you can use `Item 1`
if (selectedStatus == items[0]) TextFormField()
],
),
),
);
}
}

Related

how to use dropdownbutton with same value?

There are few same values in the dropdown button , when i tap on that it show the error ,is there any way to use the use the dropdown with same values .I have tried using the
value :
DropdownButtonHideUnderline(
child: DropdownButton2(
iconEnabledColor: primaryColor,
selectedItemHighlightColor: primaryColor,
hint: Text(
'User type',
style: TextStyle(
fontSize: 14,
color: Theme.of(context).hintColor,
),
),
items: _user_type
.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: doubl,
itemHeight: 40,
),
still getting the error
Value of every DropdownMenuItem should be unique. In order to make use of list which have repetitive values, you should have a unique identifier for each.
You can create a model:
class Model {
int id;
String value;
Model(this.id, this.value);
}
You can create list with repetitive values:
List<Model> list = [
Model(0, "a"),
Model(1, "a"),
Model(2, "b"),
Model(3, "b"),
Model(4, "c"),
Model(5, "c"),
];
…and you can use the list like this in your DropdownButton:
DropdownButton(
value: _selectedValue,
items: list
.map((value) => DropdownMenuItem(
value: value.id, child: Text(value.value)))
.toList(),
onChanged: (value) {
_selectedValue = value as int;
setState(() {});
},
)
Why don't you try adding a .toSet() before the .map().
The .toSet() should filter your list to unique values.
DropdownButtonHideUnderline(
child: DropdownButton2(
iconEnabledColor: primaryColor,
selectedItemHighlightColor: primaryColor,
hint: Text(
'User type',
style: TextStyle(
fontSize: 14,
color: Theme.of(context).hintColor,
),
),
items: _user_type
.toSet()
.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: doubl,
itemHeight: 40,
),
Try below code, I have used dropdown_button2 package
Declare your variables and dropdown data
String selectedValue;
List<String> items = [
'User 1',
'User 2',
'User 3',
'User 4',
'User 5',
'User 6',
];
Your Widget:
DropdownButtonHideUnderline(
child: DropdownButton2(
isExpanded: true,
hint: Text(
'User type',
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,
color: Colors.black,
),
overflow: TextOverflow.ellipsis,
),
))
.toList(),
value: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value as String;
});
},
buttonHeight: 50,
buttonWidth: 160,
buttonPadding: EdgeInsets.all(8),
buttonDecoration: BoxDecoration(
borderRadius: BorderRadius.circular(14),
border: Border.all(
color: Colors.black26,
),
),
itemHeight: 40,
),
),
Your Dropdown button result->
Your Dropdown data result->
You can refer my answer here, here, here also for same using dropdown_below package

change dropdown text colour from selected text

i have a dropdown which contain list of text, then i want have different color of select text and color the text from the dropdown item.
DropdownButton<String>(
hint: Text(
'Topic',
style: TextStyle(fontFamily: 'Cairo', fontSize: 20),
),
isExpanded: true,
value: dropdownValue,
dropdownColor: Colors.black,
elevation: 4,
//notices 1
style: const TextStyle(
color: Colors.deepPurple, fontFamily: 'Cairo'),
onChanged: (String? newValue) {
setState(() {
dropdownValue = newValue;
});
},
items: tpoicList
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Container(
// alignment: Alignment.centerRight,
child: Text(
value,
style: const
//notices 2
TextStyle(color: Colors.black),
),
),
);
}).toList(),
)
i notices that in the notice 1 style is also affect the notice 2 style. All i want to is to have different color in the text dropdown and selected text
what i am trying to archive
In the image you will notices the background color is different from the text color also if i select a item from the select item, the text should be in another colors
The DropdownButton has a selectedItemBuilder parameter that should solve your problem. Add something like this to your code:
selectedItemBuilder: (context) {
final List<DropdownMenuItem<String>> list = [];
for (int i = 0; i < tpoicList.lenght; i++) {
list.add(DropdownMenuItem<String>(
value: tpoicList[i],
child: Container(
child: Text(
value,
style: i == dropdownValue?
[YourNewTextStyle],
const TextStyle(color: Colors.black),
),
),
));
}
return list;
},
[official] change dropdown text colour from selected text
selectedItemBuilder: (BuildContext context) {
return tpoicList.map((String value) {
return Align(
alignment: Alignment.centerLeft,
child: Text(
dropdownValue,
style: const TextStyle(color: Colors.white),
),
);
}).toList();
},

Call a Widget based on the result of an If statement Flutter

I want to be able to call either one of two different widgets based on the result of an if statement.
I am able to get a Text Widget to show two different answers based on the result of the first dropdown box, but I am not able to call another widget the same way ...
import 'package:flutter/material.dart';
class FilterPage extends StatefulWidget {
const FilterPage({Key? key}) : super(key: key);
#override
State<FilterPage> createState() => _FilterPageState();
}
class _FilterPageState extends State<FilterPage> {
String firstDropdownValue = 'Option A';
String secondDropdownValue = 'Option B';
#override
void dispose() {
super.dispose();
}
static const String _title = 'Filter Code Sample';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
Padding(
padding: EdgeInsets.all(4),
),
],
title: Column(
children: [
Text(
'Filter',
style: TextStyle(fontSize: 22, color: Colors.amberAccent),
),
],
),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Text(
'What are the Options ?',
style: TextStyle(fontSize: 16, color: Colors.white),
),
/*
* This is the first dropdown that is called, This dropdown provides
* two possible options,
* */
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: firstDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
firstDropdownValue = newValue!;
});
},
items: <String>['Option A', 'Option B']
.map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
/*
* So this is the if Statement that works based upon the first
* drop down box's answer...
*
* The problem is I can not get the system to call another Drop down Butten
* Widget based on the answer of the first DropdownBox,
* However, i can get a Text Widget to print...
* */
Text((() {
if (firstDropdownValue == 'Option A') {
return "Option is Option A";
}
return "Option is Option B";
})()),
/*
* This is the second dropbox that I would like to be called if the
* previous statement is met instead of the Text Widget above...
*(DROPBOX 2)
* */
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: secondDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
secondDropdownValue = newValue!;
});
},
items: <String>[
'Option 1',
'Option 2',
'Option 3',
].map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
/*
* This is also drop box two, but this dropbox with these different
* options should be called when the if statement is not met ..
*(DROPBOX 2)
* */
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: secondDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
secondDropdownValue = newValue!;
});
},
items: <String>[
'Option 4',
'Option 5',
'Option 6',
].map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
],
),
),
),
);
}
}
The flow diagram is maybe easier to get the whole picture from.
You can use a if(condition)...[widgetA] else...[WidgetB] structure:
class _FilterPageState extends State<FilterPage> {
String firstDropdownValue = 'Option A';
String secondDropdownValue = 'Option B';
#override
void dispose() {
super.dispose();
}
static const String _title = 'Filter Code Sample';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
Padding(
padding: EdgeInsets.all(4),
),
],
title: Column(
children: [
Text(
'Filter',
style: TextStyle(fontSize: 22, color: Colors.amberAccent),
),
],
),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Text(
'What are the Options ?',
style: TextStyle(fontSize: 16, color: Colors.white),
),
/*
* This is the first dropdown that is called, This dropdown provides
* two possible options,
* */
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: firstDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
firstDropdownValue = newValue!;
});
},
items: <String>['Option A', 'Option B']
.map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
if(firstDropDownValue)...[
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: secondDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
secondDropdownValue = newValue!;
});
},
items: <String>[
'Option 1',
'Option 2',
'Option 3',
].map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
] else ...[
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: secondDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
secondDropdownValue = newValue!;
});
},
items: <String>[
'Option 4',
'Option 5',
'Option 6',
].map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
]
],
),
),
),
);
}
}
Not the best approach for this probably, but you can use a Builder widget, inside it put your if statement and if you don't want to show your widget there, return SizedBox.shrink() instead (don't forget to setState((){}) so that the widget containing them both rebuilds them. But a better answer may be using Bloc or some other state management package. Or even ValueNotifiers and ValueListenableBuilders to update your UI only where it's needed.
One solution here is to use an inline if condition like this:
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: firstDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
firstDropdownValue = newValue!;
});
},
items: <String>['Option A', 'Option B']
.map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
firstDropdownValue == 'Option A'?
DropdownButton(/*first dropdown*/) :
DropdownButton(/*second dropdown*/),
The other is creating a Widget variable at the beginning of the build method and giving it a value before returning the Scaffold, then put the created variable as one of the Column children:
#override
Widget build(BuildContext context) {
Widget bottomDropdown;
if (firstDropdownValue == 'Option A'){
bottomDropdown = DropdownButton(/*first dropdown*/);
} else {
bottomDropdown = DropdownButton(/*second dropdown*/);
}
return Scaffold(
appBar: AppBar(
//...other code
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: firstDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
firstDropdownValue = newValue!;
});
},
items: <String>['Option A', 'Option B']
.map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
bottomDropdown,
You can use the Dart short if form: if ? then : else.
Since the only thing that changes are the dropdown options, you can dynamically change them without the need to use another widget.
import 'package:flutter/material.dart';
class FilterPage extends StatefulWidget {
const FilterPage({Key? key}) : super(key: key);
#override
State<FilterPage> createState() => _FilterPageState();
}
class _FilterPageState extends State<FilterPage> {
String firstDropdownValue = '';
String secondDropdownValue = 'Option B';
#override
void dispose() {
super.dispose();
}
static const String _title = 'Filter Code Sample';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
Padding(
padding: EdgeInsets.all(4),
),
],
title: Column(
children: [
Text(
'Filter',
style: TextStyle(fontSize: 22, color: Colors.amberAccent),
),
],
),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Text(
'What are the Options ?',
style: TextStyle(fontSize: 16, color: Colors.white),
),
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: firstDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
firstDropdownValue = newValue!;
});
},
items: <String>['Option A', 'Option B']
.map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
if(firstDropdownValue.isNotEmpty)
DropdownButton<String>(
dropdownColor: Colors.blueGrey.shade700,
value: secondDropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.white),
underline: Container(
height: 2,
color: Colors.blueGrey.shade900,
),
onChanged: (String? newValue) {
setState(() {
secondDropdownValue = newValue!;
});
},
items: <String>[
firstDropdownValue == 'Option A' ?
...['Option 1',
'Option 2',
'Option 3'] : ...['Option 5',
'Option 6',
'Option 7']
].map<DropdownMenuItem<String>>((String doaValue) {
return DropdownMenuItem<String>(
value: doaValue,
child: Text(doaValue),
);
}).toList(),
),
],
),
),
),
);
}
}

change the flutter dropdown to textalign left

how to make the dropdown to the left, because what i get is the dropdown in the middle
DropdownButton<String>(
value: _chosenValue2,
//elevation: 5,
style: TextStyle(color: Colors.black),
items: <String>[
'Personal Type',
'Other',
].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
hint: Text(
"Customer Model",
style: TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w600),
),
onChanged: (String value) {
setState(() {
_chosenValue2 = value;
});
},
),
Try below code hope its helpful to you. Add your dropdown widget inside Container and set Alignment.centerLeft
Container(
// padding: EdgeInsets.all(5), if you required some padding to dropdown to set padding
alignment:Alignment.centerLeft,
child: DropdownButton<String>(
value: _chosenValue2,
//elevation: 5,
style: TextStyle(color: Colors.black),
items: <String>[
'Personal Type',
'Other',
].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
hint: Text(
"Customer Model",
style: TextStyle(
color: Colors.black,
fontSize: 16,
fontWeight: FontWeight.w600),
),
onChanged: (String value) {
setState(() {
_chosenValue2 = value;
});
},
),
),
Your result screen->
You could use quite a few approaches. You could wrap your drop-down widget in a Container or Align widget and set their alignment property to Alignment.bottomLeft or Alignment.centerLeft or Alignment.topLeft. You could also wrap your dropdown widget inside just a Container and then use margin property to move your widget like margin: EdgeInsets.only(right: 20) or to any value of your desire. Lastly, you could also wrap your widget with a Padding widget and set the padding property to an extent you want your drop-down widget to move leftwards like padding: const EdgeInsets.only(right: 50)

DropdownButtonFormField dosn't show the value that selected flutter

This is my code and I tried to print the value in my console to figure if it is work and it's correctly printed but it dose not show in the text Filed. When I chose the hint text disappear but no thing show also I changed the Icon (arrow) size but when I click on any part of it, no response until I click in the corner
String _medicationDesc;
List<DropdownMenuItem> getDropDownItem() {
List<DropdownMenuItem> dropDownItems = [];
for (String dose in medcationDose) {
var newItem = DropdownMenuItem(
child: Text(
dose,
style: textStyle1,
),
value: dose,
);
dropDownItems.add(newItem);
}
return dropDownItems;
}
List<String> medcationDose = [
'مرة واحدة في اليوم',
'مرتان في اليوم',
'ثلاث مرات في اليوم',
'اربعة مرات في اليوم',
'وقت الحاجة'
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(backgroundColor: nave),
body: SingleChildScrollView(
child: Container(
margin: EdgeInsets.fromLTRB(0.0, 30, 0, 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
SizedBox(
height: 50,
width: 350,
child: DropdownButtonFormField(
value: _medicationDose,
items: getDropDownItem(),
iconSize: 50,
iconEnabledColor: white,
onChanged: (value) {
setState(() {
_medicationDose = value;
});
},
decoration: InputDecoration(
hintText: 'الجرعة',
),
),
try this
List<String> languageList = ['EN', 'ES', 'FR'];
var selectedValue;
DropdownButtonHideUnderline(
child: DropdownButtonFormField<String>(
decoration: InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.transparent))),
dropdownColor: CustomColors.black,
value:
selectedValue == null ? languageList[0] : selectedValue,
style: robotoStyle(
color: CustomColors.white,
fontSize: 10),
icon: Icon(
Icons.keyboard_arrow_down,
color: CustomColors.white,
),
isExpanded: true,
items: languageList.map((item) {
return DropdownMenuItem<String>(
value: item,
child: new Text(item,
style: robotoStyle(
color: CustomColors.white,
fontSize: 10)),
);
}).toList(),
onChanged: (value) {
selectedValue = value;
S.load(Locale(selectedValue));
print(selectedValue);
},
),
)
i made a class for you, you can call it anywhere may be it will help you
class DropDownClass extends StatelessWidget {
var values;
var hint;
List list = new List();
Color underLineColor;
Color dropDownColor;
Color textColor;
DropDownClass({this.values,
this.list,this.hint,this.underLineColor,this.dropDownColor,this.textColor});
#override
Widget build(BuildContext context) {
return DropdownButtonHideUnderline(
child: DropdownButtonFormField<String>(
value: values,
dropdownColor: dropDownColor??Colors.white,
decoration: InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: underLineColor??Colors.grey[800],
width: 1.0,
),
)
),
style: TextStyle(
color: textColor??Colors.black,
fontWeight: FontWeight.w400,
fontSize: 15),
isExpanded: true,
icon: Icon(
Icons.keyboard_arrow_down,
color: Colors.white,
),
hint: Text(hint,
style: TextStyle(
color:Colors.white,
fontWeight: FontWeight.w400,
fontSize:15)),
items: list.map((item) {
return DropdownMenuItem<String>(
value: item,
child: new Text(item,
style: TextStyle(
color:Colors.black,
fontWeight: FontWeight.w400,
fontSize:15)),
);
}).toList(),
onChanged: (value) {
values = value;
print(values);
},
),
);
}
}