How to open DropDownButton on init page - flutter

i want to make a function for init openDropDown(); when page loaded or tap on other widget
I found this in stackoverfow
but its not working maybe its outdated. how can i achieve. with flutter 2.10
here is my dropdown
DropdownButton(
isExpanded: true,
value: selectedValue,
items: [
for (var i = 0; i < this.clients.length; i++)
DropdownMenuItem(
child: Text(this.clients[i]['name'].toString() +
' (' +
this.clients[i]['wallet'].toString() +
') '),
value: this.clients[i]['id'].toString())
],
onChanged: (String? newValue) {
setState(() {
selectedValue = newValue!;
});
},
),

You can take advantage of GlobalKey to get this job done... Also use SchedulerBinding because in initState key would be null so you won't be able to open DropDown from null key... here is the proper code how you do that task
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter DropDownButton',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: const MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final GlobalKey _dropdownButtonKey = GlobalKey();
final Intent _intent = const ActivateIntent();
// Initial Selected Value
String dropdownvalue = 'Item 1';
// List of items in our dropdown menu
var items = [
'Item 1',
'Item 2',
'Item 3',
'Item 4',
'Item 5',
];
#override
void initState() {
super.initState();
SchedulerBinding.instance?.addPostFrameCallback((_) {
if (_dropdownButtonKey.currentContext != null) {
_dropdownButtonKey.currentContext?.visitChildElements((element) {
if (element.widget is Semantics) {
element.visitChildElements((element) {
if (element.widget is Actions) {
element.visitChildElements((element) {
Actions.invoke(element, _intent);
return;
});
}
});
}
});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
DropdownButton(
autofocus: true,
key: _dropdownButtonKey,
isDense: true,
isExpanded: true,
value: dropdownvalue,
icon: const Icon(Icons.keyboard_arrow_down),
items: items.map((String items) {
return DropdownMenuItem(
value: items,
child: Text(items),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
dropdownvalue = newValue!;
});
},
),
],
),
),
);
}
}

Related

How to get Value to update in Flutter DropdownButton from stream?

I'm trying to get a list from my firebase firestore and provide it as a dropdown button, but when the user selects the option it does not update on GUI.
I think the problems is where I instantiate the dropdownValue variable but I don't where else to place it.
class _LocationNameListState extends State<LocationNameList> {
#override
Widget build(BuildContext context) {
List dropdownOptions = <String>[];
String? dropdownValue;
return StreamBuilder(
stream: LocationController().getAllLocations(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Text("This is something wrong");
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
for (var i = 0; i < snapshot.data!.docs.length; i++) {
dropdownOptions.add("${snapshot.data!.docs[i]['name']}");
}
print(dropdownOptions);
String dropdownValue = dropdownOptions[0];
return DropdownButton(
items: dropdownOptions
.map((e) => DropdownMenuItem(
value: e,
child: Text(e),
))
.toList(),
onChanged: (value) {
setState(() {
dropdownValue = value.toString();
print(dropdownValue);
});
},
value: dropdownValue,
);
},
);
}
}
The problem is that your dropDown value is set within your Build method:
Widget build(BuildContext context) {
List dropdownOptions = <String>[];
String? dropdown value;
return StreamBuilder(
...
So every setState it gets reset, since the build rebuilds.
To fix the error, move your value outside of the build method:
class _LocationNameListState extends State<LocationNameList> {
// --> Add this variable over here
List dropdownOptions = <String>[];
String? dropdownValue;
#override
Widget build(BuildContext context) {
...
}
I've managed to reproduce your problem with a simplified example. As you see dropdownValue will be reset, since it's within the build method:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyDropdown(),
),
),
);
}
}
class MyDropdown extends StatefulWidget {
const MyDropdown({Key? key}) : super(key: key);
#override
State<MyDropdown> createState() => _MyDropdownState();
}
class _MyDropdownState extends State<MyDropdown> {
#override
Widget build(BuildContext context) {
String dropdownValue = 'One';
return DropdownButton<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
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(),
);
}
}
And to solve the issue:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyDropdown(),
),
),
);
}
}
class MyDropdown extends StatefulWidget {
const MyDropdown({Key? key}) : super(key: key);
#override
State<MyDropdown> createState() => _MyDropdownState();
}
class _MyDropdownState extends State<MyDropdown> {
// -->Simply set the value here
String dropdownValue = 'One';
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: dropdownValue,
icon: const Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
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(),
);
}
}
Every time setState is called, build method gets called. It means
String dropdownValue = dropdownOptions[0]; is called as well setting the value of variable to first item of the list.
You need to move dropdownValue to class level variable of your state class.
(String? dropdownValue = null)
Then replace above mentioned line with
if(dropdownValue == null) {
dropdownValue = dropdownOptions[0]
}

How can I correctly use If conditionals in onPressed and setState (dart, flutter)

Im supposed to make it so that a different text appears after pressing the floating button, according to the item chosen in the dropdown menu. So, how to connect floating button to the item in dropdown menu?
Right now, when I press, nothing happens.
I have tried putting if statements in setState and then setting showText according to dropdown menu value.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'DropDownButton and FloatingActionButton',
theme: ThemeData(
primarySwatch: Colors.green,
floatingActionButtonTheme: const FloatingActionButtonThemeData(
splashColor: Colors.tealAccent,
hoverColor: Colors.redAccent,
),
),
home: const MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int showText = 1;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Geeksforgeeks"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const DropdownButtonExample(),
image(),
]
)
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.green,
child: const Icon(Icons.navigation),
onPressed: () {
if(_DropdownButtonExampleState().dropdownvalue == "Item 3"){
setState((){
showText = 1;
});
}else if (_DropdownButtonExampleState().dropdownvalue == "Item 2") {
setState((){
showText = 2;
});
}else{
setState((){
showText = 3;
});
}
}
),
);
}
image(){
if (showText == 1){
return const Text("Yo");
} else if (showText == 2){
return const Text("Hi");
} else{
return const Text("Hello");
}
}
}
class DropdownButtonApp extends StatelessWidget {
const DropdownButtonApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const Center(
child: DropdownButtonExample(),
);
}
}
class DropdownButtonExample extends StatefulWidget {
const DropdownButtonExample({Key? key}) : super(key: key);
#override
State<DropdownButtonExample> createState() => _DropdownButtonExampleState();
}
class _DropdownButtonExampleState extends State<DropdownButtonExample> {
String dropdownvalue = 'Item 1';
var items = [
'Item 1',
'Item 2',
'Item 3',
'Item 4',
'Item 5',
];
#override
Widget build(BuildContext context) {
return DropdownButton(
value: dropdownvalue,
icon: const Icon(Icons.keyboard_arrow_down),
items: items.map((String items) {
return DropdownMenuItem(
value: items,
child: Text(items),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
dropdownvalue = newValue!;
});
},
);
}
}
First of all, combine your DropdownButton widget with your MyHomePage widget, then use dropdownvalue instead of _DropdownButtonExampleState().dropdownvalue like this:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int showText = 1;
//add states here:
String dropdownvalue = 'Item 1';
var items = [
'Item 1',
'Item 2',
'Item 3',
'Item 4',
'Item 5',
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Geeksforgeeks"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
DropdownButton(
value: dropdownvalue,
icon: const Icon(Icons.keyboard_arrow_down),
items: items.map((String items) {
return DropdownMenuItem(
value: items,
child: Text(items),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
dropdownvalue = newValue!;
});
},
),
image(),
]
)
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.green,
child: const Icon(Icons.navigation),
onPressed: () {
if (dropdownvalue == "Item 3") {
setState(() {
showText = 1;
});
} else if (dropdownvalue == "Item 2") {
setState(() {
showText = 2;
});
} else {
setState(() {
showText = 3;
});
}
}
),
);
}
image() {
if (showText == 1) {
return const Text("Yo");
} else if (showText == 2) {
return const Text("Hi");
} else {
return const Text("Hello");
}
}
}

How to change value on DropdownButton in onChange in Flutter

I am a beginner in the flutter I'm just learning flutter and I am stuck in this code how to solve this please help me?
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget{
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My Application',
home: book(),
);
}
}
class book extends StatefulWidget{
#override
State<StatefulWidget> createState() {
return _bookstate();
}
}
class _bookstate extends State<book>{
String namebook = "";
var writter = ['A','B','C'];
var _currentItemSelected = 'A';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Stateful Widget'),
),
body: Container(
margin: EdgeInsets.all(20.0),
child: Column(
children:<Widget> [
TextField(
onChanged: (String userInput){
setState(() {
namebook=userInput;
});
},
),
DropdownButton<String>(
items: writter.map((String dropDownStringItem){
return DropdownMenuItem<String>(
value: dropDownStringItem,
child: Text(dropDownStringItem),
);
}).toList(),
onChanged: (String newValueSelected){
setState(() {
this._currentItemSelected = newValueSelected;
});
},
value: _currentItemSelected,
),
Text("Enter book name id $namebook",style: TextStyle(fontSize:20.0),),
],
),
),
);
}
}
and error show this message:
Error: The argument type 'void Function(String)' can't be assigned to the parameter type 'void Function(String?)?' because 'String?' is nullable and 'String' isn't.
You need to follow null safety rules, because your version supports null safety.
Simply change your code;
onChanged: (String? newValueSelected) {
setState(() {
this._currentItemSelected = newValueSelected!;
});
},
And I suggest check and learn what null safety is.
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const Book(),
);
}
}
class Book extends StatefulWidget {
const Book({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() {
return _Bookstate();
}
}
class _Bookstate extends State<Book> {
String namebook = "";
var writter = ['A', 'B', 'C'];
var _currentItemSelected = 'A';
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Stateful Widget'),
),
body: Container(
margin: const EdgeInsets.all(20.0),
child: Column(
children: <Widget>[
TextField(
onChanged: (String userInput) {
setState(() {
namebook = userInput;
});
},
),
DropdownButton<String>(
items: writter.map((String dropDownStringItem) {
return DropdownMenuItem<String>(
value: dropDownStringItem,
child: Text(dropDownStringItem),
);
}).toList(),
onChanged: (String? newValueSelected) {
setState(() {
_currentItemSelected = newValueSelected!;
});
},
value: _currentItemSelected,
),
Text(
"Enter book name id $namebook",
style: const TextStyle(fontSize: 20.0),
),
],
),
),
);
}
}

DropdownButton doesn't re-render the menu when items change

DropdownButton doesn't reflect menuItem's changes when the dropdown menu is open.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
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: Center(
child: MyStatefulWidget(),
),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
#override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
final disabledItems = ['Free', 'Four'];
List<String> items = ['One', 'Two', 'Free', 'Four'];
String dropdownValue = 'One';
#override
Widget build(BuildContext context) {
return DropdownButton<String>(
value: dropdownValue,
icon: Icon(Icons.arrow_downward),
iconSize: 24,
elevation: 16,
style: TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (String newValue) {
if (!disabledItems.contains(newValue)) {
setState(() {
dropdownValue = newValue;
});
}
},
items: items.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Row(children: [
Text(
value,
style: TextStyle(
color: disabledItems.contains(value) ? Colors.grey : null,
),
),
IconButton(
icon: Icon(Icons.delete),
color: Colors.black38,
onPressed: () {
setState(() {
items.removeWhere((element) => element == 'Two');
});
print(items.length);
},
)
]),
);
}).toList(),
);
}
}
What I aim is the chance of removing an item from the menu when the delete icon is pressed. All the expected events are working as expected and the DropDown items list is updating accordingly in the backend but it doesn't re-render.
DorpDown Menu with delete icon
In order to be able to see the updated items list I have to close the dropdown menu and open it again but this doesn’t feel right in terms of user experience.

DropdownButtonFormField assertion fails where DropdownButtonHideUnderline doesn't

This works with DropdownButtonHideUnderline, but does not work with DropdownButtonFormField. I want the inputDecoration that I get with DropdownButtonFormField, but this code fails at runtime when I change the project.
I either need to fix it to run with DropdownButtonFormField or I should find a way to get the inputDecoration added to the DropdownButtonHideUnderline;
At runtime the error that comes out is:
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value
'package:flutter/src/material/dropdown.dart':
Failed assertion: line 827 pos 15: 'items == null || items.isEmpty || value == null ||
items.where((DropdownMenuItem<T> item) {
return item.value == value;
}).length == 1'
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
Map data = {
'Project 1': ['Entrance', 'Main Hallway', 'Kitchen'],
'Project 2': ['Patio', 'Dining Room'],
};
class _MyHomePageState extends State<MyHomePage> {
String _project;
String _room;
List<String> _roomList = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
children: <Widget>[
DropdownButtonFormField(
decoration: InputDecoration(labelText: 'Project'),
value: _project,
onChanged: (value) {
setState(() {
_project = value;
_room = null;
_roomList = data[_project];
});
},
items: data.keys.map((item) {
return DropdownMenuItem(
child: Text(item),
value: item,
);
})?.toList() ??
[],
),
DropdownButtonFormField(
decoration: InputDecoration(labelText: 'Room'),
value: _room,
onChanged: (value) {
setState(() {
_room = value;
print(_project);
print(_room);
});
},
items: _roomList.map((item) {
return DropdownMenuItem(
child: Text(item),
value: item,
);
})?.toList() ??
[],
),
],
),
));
}
}
You can copy paste run full code below
When Dropdown list data is totally different will trigger this error
For Room DropdownButtonFormField You can use key: UniqueKey() and widget will recreate
code snippet
DropdownButtonFormField(
key: UniqueKey(),
decoration: InputDecoration(labelText: 'Room'),
working demo
full code
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
Map data = {
'Project 1': ['Entrance', 'Main Hallway', 'Kitchen'],
'Project 2': ['Patio', 'Dining Room'],
};
class _MyHomePageState extends State<MyHomePage> {
String _project;
String _room;
List<String> _roomList = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
children: <Widget>[
DropdownButtonFormField(
decoration: InputDecoration(labelText: 'Project'),
value: _project,
onChanged: (value) {
setState(() {
_project = value;
_room = null;
_roomList = data[_project];
});
},
items: data.keys.map((item) {
return DropdownMenuItem(
child: Text(item),
value: item,
);
})?.toList() ??
[],
),
DropdownButtonFormField(
key: UniqueKey(),
decoration: InputDecoration(labelText: 'Room'),
value: _room,
onChanged: (value) {
setState(() {
_room = value;
print(_project);
print(_room);
});
},
items: _roomList.map((item) {
return DropdownMenuItem(
child: Text(item),
value: item,
);
})?.toList() ??
[],
),
],
),
));
}
}