How to implement dropdownbutton into a function in flutter - flutter

Im working on a company project. But I can't simply get the idea of how to implement a basic dropdown button into a function but I can't seem to make the values change in the dropdown function what do you think im doing wrong here's my code:
Widget buildDropdownField({
required String dropdownHeader,
required String dropdownValue,
}) {
return Column(
children: <Widget>[
Text(dropdownHeader),
const SizedBox(
height: 10,
),
//dropdownField
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? newValue) {
setState(() {
dropdownValue = newValue!;
});
},
items: <String>['-', 'Geçti', 'Kaldı', 'Belirsiz']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)
],
);
}

Wrap with StatefulBuilder it will work.
Widget buildDropdownField(
{required String dropdownHeader, required String dropdownValue}) {
return Column(
children: <Widget>[
Text(dropdownHeader),
const SizedBox(
height: 10,
),
StatefulBuilder(
builder: (_, setDropState) {
return 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? newValue) {
setDropState(() {
dropdownValue = newValue!;
});
},
items: <String>['-', 'Geçti', 'Kaldı', 'Belirsiz']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
},
)
],
);
}

Try below code hope its help to you. use StatefulBuilder Refer here
Your dropdown function:
buildDropdownField({
required String dropdownHeader,
required String dropdownValue,
}) {
return Column(
children: <Widget>[
Text(dropdownHeader),
const SizedBox(
height: 10,
),
//dropdownField
StatefulBuilder(builder: (context, StateSetter setState) {
return 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? newValue) {
setState(() {
dropdownValue = newValue!;
});
},
items: <String>['-', 'Geçti', 'Kaldı', 'Belirsiz']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
);
})
],
);
}
Your Widget:
buildDropdownField(
dropdownHeader: 'dropdownHeader',
dropdownValue: '-',
),
Result->
Result after selection->

First of all, you shouldn't update the parameter with the new value. It did update the parameter, but the function will still getting the value from it's calling.
I did not know the buildDropdownField function is inside a class or not, but it's okay and I will provide the solutions for both scenarios.
Within the Class
You need to create a variable within a class outside the functions.
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _dropDownValue = '-';
Widget buildDropdownField({required String dropdownHeader}) {
return Column(
children: <Widget>[
Text(dropdownHeader),
const SizedBox(
height: 10,
),
//dropdownField
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? newValue) {
setState(() {
_dropDownValue = newValue!;
});
},
items: <String>['-', 'Geçti', 'Kaldı',
'Belirsiz'].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)
],
);
}
}
Outside the Class
You need to turn it into Stateful Widget in order for the drop down text to change. Once the dropdown is a stateful widget, you can use the solution above or a callback to make the changes on parent class.
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _dropDownValue = '-';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: DropDownWidget(
dropdownHeader: 'Name',
dropdownValue: _dropDownValue,
onChanged: (String? newValue) {
setState(() {
_dropDownValue = newValue!;
});
},
),
),
);
}
}
class DropDownWidget extends StatefulWidget {
final String dropdownHeader;
final String dropdownValue;
final Function(String?)? onChanged;
DropDownWidget({required this.dropdownHeader, required this.dropdownValue, this.onChanged, Key? key}) : super(key: key);
#override
_DropDownWidgetState createState() => _DropDownWidgetState();
}
class _DropDownWidgetState extends State<DropDownWidget> {
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Text(widget.dropdownHeader),
const SizedBox(
height: 10,
),
//dropdownField
DropdownButton<String>(
value: widget.dropdownValue,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: widget.onChanged,
items: <String>['-', 'Geçti', 'Kaldı', 'Belirsiz'].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
)
],
);
}
}

Related

reset dropdown menu flutter

how to reset dropdonw to defult value after press button ?
i am trying to press button to reset dropdownmune to its defualt
class drawarScreen extends StatelessWidget {
const drawarScreen({super.key});
#override
Widget build(BuildContext context) {
List<String> list = <String>['One', 'Two', 'Three', 'Four'];
String? dropdownValue;
return Scaffold(
body: Column(children:[
DropdownButton<String>(
hint: Text('moammed'),
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(),
);
},
ElevatedButton(
onPress:(){
setstate({
dropdownValue='';
});
},child: Text("reste");
)
]);
}
}
i am trying to press button to reset dropdownmune to its defualt
resat dropdown menu in flutter
You need to put null value instead of empty string
setstate({
dropdownValue = null ;
});
If you like to have other than null, put it there.
And make sure to have StatefulWidget and variables outside the build method.
Full widget
class drawarScreen extends StatefulWidget {
const drawarScreen({super.key});
#override
State<drawarScreen> createState() => _drawarScreenState();
}
class _drawarScreenState extends State<drawarScreen> {
List<String> list = <String>['One', 'Two', 'Three', 'Four'];
String? dropdownValue;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
DropdownButton<String>(
hint: Text('moammed'),
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) {
setState(() {
dropdownValue = value;
});
},
items: list.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
ElevatedButton(
onPressed: () {
setState(() {
dropdownValue = null;
});
},
child: Text("Reset"))
],
),
);
}
}

My Flutter ListView is always removing the last item from the list

I'm creating a Flutter Widget and when I try to remove an item from the list I'm using, it always removes the last one, I was thinking it could be a Key problem, but nothing suits it, do anyone know how I could solve this?
The code
create_game.dart
import 'package:flutter/material.dart';
import 'package:pontinho/components/custom_input.dart';
class CreateGame extends StatefulWidget {
const CreateGame({super.key});
#override
State<CreateGame> createState() => _CreateGameState();
}
class _CreateGameState extends State<CreateGame> {
List<String> names = [''];
void changeName(int nameIndex, String change) {
setState(() {
names[nameIndex] = change;
});
}
void removeName(int nameIndex) {
print(names);
print(nameIndex);
setState(() {
names.removeAt(nameIndex);
});
}
ListView createNamesInput() {
return ListView.builder(
itemCount: names.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return ListTile(
key: ObjectKey(index),
title: CustomInput(
key: ObjectKey(index),
labelText: "Nome",
onChanged: (String changed) => changeName(index, changed),
text: names[index],
onRemoved: () => removeName(index),
),
);
},
);
// return names
// .asMap()
// .entries
// .map((el) => CustomInput(
// key: ObjectKey('${el.key}'),
// labelText: "Nome",
// onChanged: changeName,
// index: el.key,
// text: names[el.key],
// onRemoved: removeName,
// ))
// .toList();
}
void addName() {
setState(() {
names.add('');
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: GestureDetector(
onTap: (() => Navigator.pop(context)),
child: const Icon(
Icons.arrow_back,
color: Colors.black,
size: 40,
),
),
backgroundColor: Colors.white,
titleTextStyle: const TextStyle(
color: Colors.black,
fontSize: 20,
),
title: const Text("CRIE SEU JOGO"),
),
body: Padding(
padding: const EdgeInsets.symmetric(
vertical: 8,
horizontal: 16,
),
// child: createNamesInput(),
child: Column(
children: [
createNamesInput(),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: addName,
child: Row(
children: const [
Icon(Icons.add),
Text('Adicionar Jogador'),
],
),
),
],
),
),
SizedBox(
width: double.infinity,
height: 50,
child: ElevatedButton(
onPressed: () => print('Iniciar!'),
child: const Text('Iniciar!'),
),
)
],
),
),
);
}
}
custom_input.dart
import 'package:flutter/material.dart';
typedef OneArgumentCallback = void Function(String changed);
class CustomInput extends StatefulWidget {
final OneArgumentCallback onChanged;
final VoidCallback onRemoved;
final String labelText;
final String text;
const CustomInput({
super.key,
required this.onChanged,
required this.labelText,
required this.text,
required this.onRemoved,
});
#override
State<CustomInput> createState() => _CustomInputState();
}
class _CustomInputState extends State<CustomInput> {
late final TextEditingController inputController;
#override
void initState() {
super.initState();
inputController = TextEditingController(text: widget.text);
}
void changeContent(String value) {
widget.onChanged(
value,
);
}
#override
Widget build(BuildContext context) {
return TextFormField(
key: widget.key,
controller: inputController,
textDirection: TextDirection.ltr,
decoration: InputDecoration(
border: const UnderlineInputBorder(),
labelText: widget.labelText,
suffixIcon: IconButton(
onPressed: () => widget.onRemoved(),
icon: const Icon(
Icons.close,
color: Colors.red,
),
),
),
autocorrect: false,
onChanged: (value) => changeContent(value),
);
}
}
Indeed it is a key issue, you have to create a combined key that must be unique for each item, I merged the index with names[index],
CustomInput(
key: ObjectKey('$index:${names[index]}'),
labelText: "Nome",
onChanged: (String changed) => changeName(index, changed),
text: names[index],
onRemoved: () => removeName(index),
),
note that if you try this code alone the textfield will lose focus because the key has changed, this will be solved by removing the setState inside the onChange
void changeName(int nameIndex, String change) {
names[nameIndex] = change;
}
here you don't need setState because the UI will be updated by default when you are typing in the textfield
I hope I made it clear
I was thinking it could be a Key problem
That's correct; You need to use names[index] as the value for your Key:
ListTile(
key: ObjectKey(names[index]),
title: CustomInput(

Selected item not showing in DropdownButton in Flutter

I need your help. I'm making a DropdownButton and I'm facing the following problem - I can't see the items that are selected in the DropdownMenuItems. I do not understand what the problem is that nothing is displayed. I'm using the [getwidget][1] package it's a GFCheckboxListTile widget - which just adds a checkbox. Please tell me how can I fix this error?
dropdown
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:getwidget/getwidget.dart';
import 'package:joyn/constants/constants.dart' as constants;
class DropdownWidget extends StatefulWidget {
List<String> items;
SvgPicture? icon;
double width;
DropdownWidget({
Key? key,
required this.items,
required this.icon,
required this.width,
}) : super(key: key);
#override
State<DropdownWidget> createState() => _DropdownWidgetState();
}
class _DropdownWidgetState extends State<DropdownWidget> {
String? selectedValue;
bool selected = false;
final List _selectedTitles = [];
final List _selectedTitlesIndex = [];
final GFCheckboxType type = GFCheckboxType.basic;
#override
void initState() {
super.initState();
if (widget.items.isNotEmpty) {
_selectedTitles.add(widget.items[1]);
}
}
void _onItemSelect(bool selected, int index) {
if (selected == true) {
setState(() {
_selectedTitles.add(widget.items[index]);
_selectedTitlesIndex.add(index);
});
} else {
setState(() {
_selectedTitles.remove(widget.items[index]);
_selectedTitlesIndex.remove(index);
});
}
}
#override
Widget build(BuildContext context) {
return SizedBox(
width: widget.width,
child: DropdownButtonHideUnderline(
child: DropdownButton(
items: List.generate(
widget.items.length,
(index) => DropdownMenuItem<String>(
value: widget.items[index],
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: constants.Colors.white.withOpacity(0.1),
width: 1,
),
),
),
child: GFCheckboxListTile(
value: _selectedTitles.contains(widget.items[index]),
onChanged: (bool selected) {
_onItemSelect(selected, index);
},
selected: selected,
title: Text(
widget.items[index],
style: constants.Styles.smallTextStyleWhite,
),
padding: const EdgeInsets.only(top: 14, bottom: 13),
margin: const EdgeInsets.only(right: 12, left: 2),
size: 22,
activeBgColor: constants.Colors.greyCheckbox,
activeBorderColor: Colors.red,
inactiveBgColor: constants.Colors.greyCheckbox,
activeIcon: SvgPicture.asset(constants.Assets.checkboxIcon),
inactiveBorderColor: constants.Colors.greyXMiddle,
type: type,
),
),
),
),
value: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value as String;
});
},
icon: SvgPicture.asset(constants.Assets.arrowDropdown),
iconSize: 21,
itemHeight: 66,
selectedItemBuilder: (context) {
return _selectedTitles.map(
(item) {
return Row(
children: [
widget.icon ?? const SizedBox(),
const SizedBox(width: 8),
Text(
item,
style: constants.Styles.bigBookTextStyleWhite,
),
],
);
},
).toList();
},
),
),
);
}
}
While the UI is need to update on DropdownMenuItem you can wrap GFCheckboxListTile with StatefulBuilder.
child: Container(
child: StatefulBuilder(
builder: (context, setStateSB) => GFCheckboxListTile(
value: _selectedTitles.contains(widget.items[index]),
onChanged: (bool selected) {
_onItemSelect(selected, index);
setStateSB(() {}); /// we are using StatefulBuilder's setState
///add your logic then
setState(() {
selectedValue = widget.items[index];
});
},
DropdownMenuItem ontap is outSide the GFCheckboxListTile therefore onChanged is not calling. I am using onChanged from GFCheckboxListTile to update the selectedValue.

Nesting ListView into DropdownMenu

I have created a custom ListView and I want to nest it into my Dropdownmenu as the item. Currently, I am getting the 'NoSuchMethodError : The method 'map' was called on null'. I can't seem to map it right. I am very new to Flutter.
The code for the ListView
class TheDetails extends StatelessWidget {
TheDetails({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView(
padding: const EdgeInsets.all(8.0),
itemExtent: 70.0,
children: <CustomListItem>[
CustomListItem(
accName: 'Salary Account',
accNumber: 'Savings XXX-X-XX563-9',
accBalance: '56,302.56',
),
CustomListItem(
accName: 'Salary Account 2',
accNumber: 'Savings XXX-X-XX563-9',
accBalance: '89,302.56',
),
CustomListItem(
accName: 'Vayu Meetang',
accNumber: 'Savings XXX-X-XX563-9',
accBalance: '100,505.56',
),
],
);
}
}
The code for the DropdownButton
class SelectAccount extends StatefulWidget {
#override
_SelectAccountState createState() => _SelectAccountState();
}
class _SelectAccountState extends State<SelectAccount> {
var dropdownValue;
var accountNames;
#override
Widget build(BuildContext context) {
return Container(
constraints: BoxConstraints.expand(width: 375.0, height: 120.0),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(20.0),
),
child: DropdownButton<String>(
value: dropdownValue,
underline: Container(
height: 2,
),
icon: Icon(Icons.keyboard_arrow_down,
color: Colors.blue[500],),
onChanged: (String newValue) {
setState(() {
dropdownValue = newValue;
});
},
items: accountNames.map((item){
return DropdownMenuItem(
value: item,
child: TheDetails(),
);
}).toList(),
),
);
}
}
You're calling .map() on accountNames which is not initialized, and therefore null at least on the first build. So doing var accountNames = []; will solve the issue.
A cleaner way to add a widget for each member of a list is :
items: [
for(var name in accountNames)
DropdownMenuItem(value: name, child: TheDetails()),
]
EDIT: Putting everything together :
// in top-level or another file
class Account {
Account(this.name, this.number, this.balance);
String name;
String number;
String balance;
}
// in _SelectAccountState or a provider
var selectedAccount = 'Savings XXX-X-XX563-9';
var accounts = [
Account(
'Salary Account',
'Savings XXX-X-XX563-7',
'56,302.56',
),
Account(
'Salary Account 2',
'Savings XXX-X-XX563-8',
'89,302.56',
),
Account(
'Vayu Meetang',
'Savings XXX-X-XX563-9',
'100,505.56',
),
];
// In the build method
DropdownButton<String>(
value: selectedAccount,
items: [
for(var account in accounts)
DropdownMenuItem<String>(
value: account.number,
child: Text(account.name),),
],
onChanged: (val) => setState(() => selectedAccount = val)
),

Dropdownbutton value in flutter not changing during onchange event

I am new to using a Dropdownbutton but I copied this code from a material example and the value is not changing when I pick a different category. Im not sure whats going on but the value changes internally when I debug but the displayed text stays at the default setting which is "Choose a goal category".
DropdownButton<String>(
value: dropdownValue,
icon: Icon(Icons.check_circle_outline),
iconSize: 24,
elevation: 16,
style: TextStyle(
color: Colors.blue[300]
),
underline: Container(
height: 2,
color: Colors.blue[300],
),
onChanged: (String newValue) {
setState(() {
dropdownValue = newValue;
updateCategory(newValue);
});
},
items: <String>['Choose a goal category', 'Financial', 'Physical', 'Family', 'Mental', 'Social', 'Spiritual', 'Personal']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
})
.toList(),
),
Replace this.
items : <String>['Choose a goal category', 'Financial', 'Physical', 'Family', 'Mental', 'Social', 'Spiritual', 'Personal']
.map((String dropDownStringItem){
return DropdownMenuItem<String>{
value : dropDownStringItem,
...
}
}).toList(),
I hope to help you
Step 1: declare String dropdownValue; do not set value
Step 2: use hint and set to Text('Choose a goal category')
Step 3: items remove string "Choose a goal category"
code snippet
String dropdownValue;
...
DropdownButton<String>(
hint: Text('Choose a goal category'),
value: dropdownValue,
icon: Icon(Icons.check_circle_outline),
iconSize: 24,
elevation: 16,
style: TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.blue[300],
),
onChanged: (String newValue) {
setState(() {
dropdownValue = newValue;
});
},
items: <String>[
'Financial', 'Physical', 'Family', 'Mental', 'Social', 'Spiritual', 'Personal'
].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
full code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: MyStatefulWidget(),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
#override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
String dropdownValue;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Center(
child: DropdownButton<String>(
//isDense: true,
hint: Text('Choose a goal category'),
value: dropdownValue,
icon: Icon(Icons.check_circle_outline),
iconSize: 24,
elevation: 16,
style: TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.blue[300],
),
onChanged: (String newValue) {
setState(() {
dropdownValue = newValue;
});
},
items: <String>[
'Financial', 'Physical', 'Family', 'Mental', 'Social', 'Spiritual', 'Personal'
].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
),
],
),
);
}
}