Cannot remove the current snackbar by calling ScaffoldState().removeCurrentSnackBar() - flutter

For some reason i am not able to remove the current snackbar even though i am calling ScaffoldState().removeCurrentSnackBar()
I am not getting any error messages, but for some reason the snackbar wont go away. Any other way to remove the snackbar when the user picks an item from the DropdownButton?
I have already tried ScaffoldState().hideCurrentSnackBar() and all the other funncntions which are supposed to remove the SnackBar.
Thank you for your answer.
class MainRoute extends StatefulWidget {
#override
_MainRouteState createState() => _MainRouteState();
}
class _MainRouteState extends State<MainRoute> {
List<Currency> dropdownItems = [
Currency(currencyName: "FOO", currencyInUSD: 22.0),
Currency(currencyName: "BOO", currencyInUSD: 22.0),
Currency(currencyName: "SOO", currencyInUSD: 22.0),
];
Currency dropdownValue;
Color color = Colors.green;
MainModel model = MainModel();
#override
void initState() {
super.initState();
dropdownValue = dropdownItems[0];
}
#override
Widget build(BuildContext context) {
return Scaffold(
///A Builder has been added so the context contains the Scaffold which
///is required to create a SnackBar
floatingActionButton: Builder(
builder: (context) {
return FloatingActionButton(
child: Icon(
Icons.add,
color: kIconColor,
),
onPressed: () {
print(dropdownItems.map((item) {
return DropdownMenuItem(
value: item,
child: Text(item.currencyName),
);
}).toList());
setState(() {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text('Which currency do you want to add to your list?'),
SizedBox(
height: 25.0,
),
DropdownButton<Currency>(
items: dropdownItems
.map<DropdownMenuItem<Currency>>((item) {
return DropdownMenuItem(
value: item,
child: Text(item.currencyName),
);
}).toList(),
value: dropdownValue,
onChanged: (value) {
setState(() {
dropdownValue = value;
ScaffoldState().removeCurrentSnackBar(
reason: SnackBarClosedReason.remove);
print("SnackBar removed");
});
},
)
],
),
action: SnackBarAction(
label: 'Cancel',
onPressed: () {
print('Cancel');
},
),
),
);
});
},
);
},
),
);
}
}

As for 2021, you should use
ScaffoldMessenger.of(context).removeCurrentSnackBar()
instead of
Scaffold.of(context).removeCurrentSnackBar();
This feature was deprecated after Flutter v1.23.0-14.0.pre.

Instead of using the following onChanged method when the user picks an item from the DropdownButton:
onChanged: (value) {
setState(() {
dropdownValue = value;
ScaffoldState().removeCurrentSnackBar(
reason: SnackBarClosedReason.remove);
print("SnackBar removed");
});
),
Use this method call instead to remove the snackbar:
onChanged: (value) {
setState(() {
dropdownValue = value;
Scaffold.of(context).removeCurrentSnackBar(
reason: SnackBarClosedReason.remove,
);
print("SnackBar removed");
});
),

Related

TextField widgets lose focus (Flutter)

I am creating an app with Flutter TextField widgets:
class CategoryData {
int? id;
String name;
String description;
CategoryData({this.id, required this.name, required this.description});
}
class CategoriesEdit extends StatefulWidget {
Database? db;
CategoryData? category;
CategoriesEdit({super.key, required this.db, required this.category});
#override
State<StatefulWidget> createState() => CategoriesEditState();
}
class CategoriesEditState extends State<CategoriesEdit> {
CategoryData? category;
void saveState(BuildContext context) {
// ...
}
#override
Widget build(BuildContext context) {
if (category == null) {
setState(() {
category = widget.category ?? CategoryData(name: "", description: "");
});
}
return Scaffold(
appBar: AppBar(
leading: InkWell(
child: const Icon(Icons.arrow_circle_left),
onTap: () => Navigator.pop(context)),
title: const Text("Edit Category"),
),
body: Column(children: [
Column(key: const Key('name'), children: [
const Text("Category name:*"),
TextField(
controller: TextEditingController(text: category!.name),
onChanged: (value) {
setState(() {
category!.name = value;
});
})
]),
Column(key: const Key('description'), children: [
const Text("Description:"),
TextField(
controller: TextEditingController(text: category!.description),
onChanged: (value) {
setState(() {
category!.description = value;
});
})
]),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
ElevatedButton(
onPressed: () => saveState(context), // passing false
child: const Text('OK'),
),
OutlinedButton(
onPressed: () => Navigator.pop(context, false),
// passing false
child: const Text('Cancel'),
),
]),
]));
}
}
But after I type a character in one of these two widgets, the cursor moves before the first character and the Android keyboard widget disappears. Why? And how to fix that bug?
I tried adding widget keys, but as you see it didn't help.
There is a lot of things going wrong here, not only the stuff mentioned in the other answer.
Move the setState in the builder into initState:
if (category == null) {
setState(() {
category = widget.category ?? CategoryData(name: "", description: "");
});
}
Don't use setState in the onChanged callback. Change:
onChanged: (value) {
setState(() {
category!.description = value;
});
}
to this:
onChanged: (value) {
category!.description = value;
}
Store the TextEditingControllers, because you have to dispose them once we dispose the state.
If you are already using TextEditingControllers, then you don't need the onChanged callback. Just take text from the controller like explained in the other answer.
You do not have to do
controller: TextEditingController(text: category!.name)
because the controller's text automatically changes once you connect it to TextField.
The reason is once you set some text to the controller, it re-applies the text thus moving the cursor to the front.
I have solved this for you :
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class CategoryData {
int? id;
String name;
String description;
CategoryData({this.id, required this.name, required this.description});
}
class CategoriesEdit extends StatefulWidget {
CategoryData? category;
CategoriesEdit({required this.category});
#override
State<StatefulWidget> createState() => CategoriesEditState();
}
class CategoriesEditState extends State<CategoriesEdit> {
CategoryData? category;
// Database? db;
TextEditingController nametextController = TextEditingController();
TextEditingController descriptionTextController = TextEditingController();
void saveState(BuildContext context) {
// ...
}
#override
Widget build(BuildContext context) {
if (category == null) {
setState(() {
category = widget.category ?? CategoryData(name: "", description: "");
});
}
nametextController.text = category!.name??"";
descriptionTextController.text = category!.description??"";
return Scaffold(
appBar: AppBar(
leading: InkWell(
child: const Icon(Icons.arrow_circle_left),
onTap: () => Navigator.pop(context)),
title: const Text("Edit Category"),
),
body: Column(children: [
Column(key: const Key('name'), children: [
const Text("Category name:*"),
TextField(
controller: nametextController,
onChanged: (value) {
setState(() {
category!.name = value;
});
})
]),
Column(key: const Key('description'), children: [
const Text("Description:"),
TextField(
controller: descriptionTextController,
onChanged: (value) {
setState(() {
category!.description = value;
});
})
]),
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
ElevatedButton(
onPressed: () => saveState(context), // passing false
child: const Text('OK'),
),
OutlinedButton(
onPressed: () => Navigator.pop(context, false),
// passing false
child: const Text('Cancel'),
),
]),
]));
}
}
I have tested this code and it is working fine, let me know if you have any doubt. Hope this helps you.

having trouble with Flutter null safety, database object refuses to initialize

I have been trying to implement a simple To Do app without providers (for the course's sake) to advance in the course at the pace the instructor intended. But I cannot seem to find a solution for this small problem..
in the below code, the variable database does not want to be initialized whatsoever. The getData() method that's supposed to retrieve data (query) doesn't initialize the variable database even if I call it in createDatabase() in initState() It keeps giving the following errors:
''' I/flutter ( 5171): error LateInitializationError: Field 'database' has not been initialized. during open, closing...
E/flutter ( 5171): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: LateInitializationError: Field 'database' has not been initialized.
'''
import 'package:intl/intl.dart';
import 'package:sqflite/sqflite.dart';
import 'package:to_do_app/modules/todo_app/archived/archived_screen.dart';
import 'package:to_do_app/modules/todo_app/done/done_screen.dart';
import 'package:to_do_app/modules/todo_app/tasks/tasks_screen.dart';
class HomeLayout extends StatefulWidget {
const HomeLayout({ Key? key }) : super(key: key);
#override
State<HomeLayout> createState() => _HomeLayoutState();
}
class _HomeLayoutState extends State<HomeLayout> {
int currentIndex = 0;
List<String> titles = [
'Tasks',
'Done Tasks',
'Archived Tasks',
];
List<Map> tasks = [];
late Database database;
var scaffoldKey = GlobalKey<ScaffoldState>();
bool isOpen = false;
IconData fabIcon = Icons.edit;
var titleController = TextEditingController();
var dateController = TextEditingController();
var timeController = TextEditingController();
var formKey = GlobalKey<FormState>();
#override
void initState() {
super.initState();
createDatabase();
}
#override
Widget build(BuildContext context) {
List <Widget> screens = [
NewTasksScreen(),
DoneTasksScreen(),
ArchivedTasksScreen()
];
return Scaffold(
key: scaffoldKey,
appBar: AppBar(
title: Text(titles[currentIndex]),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
if(isOpen == false){
isOpen = true;
setState(() {
fabIcon = Icons.add;
});
scaffoldKey.currentState!.showBottomSheet(
(context) => SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20),
child: Form(
key: formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextFormField(
validator: (value){
if(value!.isEmpty){
return 'title must not be empty';
}
},
controller: titleController,
decoration: InputDecoration(
labelText: 'Title',
prefixIcon: Icon(
Icons.title
),
),
),
SizedBox(height: 10),
TextFormField(
onTap: (){
showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime.now(),
lastDate: DateTime(2025)
).then((value) {
dateController.text = DateFormat.yMMMMd().format(value!);
});
},
validator: (value){
if(value!.isEmpty){
return 'date must not be empty';
}
},
controller: dateController,
decoration: InputDecoration(
labelText: 'Date',
prefixIcon: Icon(
Icons.date_range
),
),
),
SizedBox(height: 10),
TextFormField(
onTap: (){
showTimePicker(
context: context,
initialTime: TimeOfDay.now()
).then((value) {
timeController.text = value!.format(context);
});
},
validator: (value){
if(value!.isEmpty){
return 'time must not be empty';
}
},
controller: timeController,
decoration: InputDecoration(
labelText: 'Time',
prefixIcon: Icon(
Icons.timer
),
),
),
],
),
),
),
),
).closed.then(
(value) {
isOpen = false;
}
);
} else {
if (formKey.currentState!.validate()) {
insertIntoDatabase(
title: titleController.text,
date: dateController.text,
time: timeController.text
).then((value) {
Navigator.pop(context);
isOpen = false;
setState(() {
fabIcon = Icons.edit;
});
});
}
}
},
child: Icon(
fabIcon
),
),
bottomNavigationBar: BottomNavigationBar(
elevation: 20,
type: BottomNavigationBarType.fixed,
currentIndex: currentIndex,
items: [
BottomNavigationBarItem(
icon: Icon(
Icons.task_alt
),
label: 'new tasks'
),
BottomNavigationBarItem(
icon: Icon(
Icons.done
),
label: 'done tasks'
),
BottomNavigationBarItem(
icon: Icon(
Icons.archive_outlined
),
label: 'archived tasks'
)
],
onTap: (index){
setState(() {
currentIndex = index;
});
},
),
body: screens[currentIndex],
);
}
Future getName() async {
return 'Ahmad Ali';
}
void createDatabase() async {
database = await openDatabase(
'todo.db',
version: 1,
onCreate: (database, version) {
print('databse created');
database.execute(
'CREATE TABLE tasks(id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, date TEXT, time TEXT, status TEXT)'
).then(
(value) {
print('table created');
}
).catchError(
(error){
print('error creating table ${error.toString()}');
}
);
},
onOpen: (databse) async {
print('database opened');
await getData(database).then((value) {
tasks = value;
print(tasks);
});
}
);
}
Future insertIntoDatabase({
required String title,
required String date,
required String time
}
) async {
return await database.transaction(
(txn) {
return txn.rawInsert(
'INSERT INTO tasks (title, date, time, status) VALUES ("$title", "$date", "$timeController", "new")'
).then(
(value) {
print('$value inserted succsessfully');
}
).catchError(
(error){
print('error inserting into table ${error.toString()}');
}
);
}
);
}
Future<List<Map>> getData(Database database) async {
return await database.rawQuery('SELECT * FROM tasks');
}
} ```
Try to initialize
late Database database;
in the StatefulWidget instead of it's State and in the createDatabase() call it like
widget.database = await OpenDatabase...
Also try to see if adding await in initState helps.
instead of
late Database database;
Write
static Database? database;

Flutter: A value of type 'GameNameEnum' can't be assigned to a variable of type 'GameNameEnum'

I am getting a really strange error in my code. When I try to use _dialogPlatform = newValue; or _dialogGameName = newValue; I get a red highlight by VS code saying I cannot assign a value with some type to a variable of the same type.
Complete error: A value of type 'Platform' can't be assigned to a variable of type 'Platform'.
Try changing the type of the variable, or casting the right-hand type to 'Platform'.
Please help.
import 'package:all_gta_cheats/enums/enums.dart';
import 'package:all_gta_cheats/widgets/drop_down_menu.dart';
import 'package:flutter/material.dart';
class FilterDialogBox extends StatefulWidget {
const FilterDialogBox({
Key? key,
required this.initialPlatformValue,
required this.initialGameNameValue,
required this.initialIsFavValue,
required this.onApply,
}) : super(key: key);
final Platform initialPlatformValue;
final GameNameEnum initialGameNameValue;
final bool initialIsFavValue;
final Function(
Platform platform,
GameNameEnum gameNameEnum,
bool isFav,
) onApply;
#override
_FilterDialogBoxState createState() => _FilterDialogBoxState();
}
class _FilterDialogBoxState extends State<FilterDialogBox> {
final TextStyle actionsTextStyle = TextStyle(fontSize: 18);
late GameNameEnum _dialogGameName;
late Platform _dialogPlatform;
late bool _dialogIsFav;
#override
void initState() {
super.initState();
_dialogGameName = widget.initialGameNameValue;
_dialogPlatform = widget.initialPlatformValue;
_dialogIsFav = widget.initialIsFavValue;
}
#override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Search Filter'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
DropDownMenu<Platform>(
initialValue: _dialogPlatform,
itemsList: Platform.values,
onChanged: <Platform>(newValue) {
//Platform value changes here
_dialogPlatform = newValue;
print(newValue.toString());
},
),
DropDownMenu<GameNameEnum>(
initialValue: _dialogGameName,
itemsList: GameNameEnum.values,
onChanged: <GameNameEnum>(newValue) {
//GameName value changes here
_dialogGameName = newValue;
print(newValue.toString());
},
),
SwitchListTile(
title: const Text('Show only favourites'),
value: _dialogIsFav,
onChanged: (bool value) {
setState(() {
_dialogIsFav = value;
print(_dialogIsFav);
//widget.dialogIsFav = value;
});
},
secondary: const Icon(Icons.favorite),
),
],
),
),
actions: <Widget>[
TextButton(
child: Text(
'Cancel',
style: actionsTextStyle,
),
onPressed: () {
Navigator.of(context).pop();
},
),
TextButton(
child: Text(
'Apply',
style: actionsTextStyle,
),
onPressed: () {
widget.onApply(_dialogPlatform, _dialogGameName, _dialogIsFav);
Navigator.of(context).pop();
},
),
],
);
}
}

Related DropdownButtons and raising onChange event

I have two DropdownButton widget. Content of second one depends on first one selection. Second DropdownButton will initiate refresh of third widget. How can I initiate refresh of second DropdownButton when first one is populated? And then how can I refresh third widget when second DropdownButton populated also?
class ParentBloc {
Stream<List<Parent>> get items => _controller.asyncMap(...);
Future<List<Parent>> _callApi() {
// call endpoint /parents
}
}
class ChildBloc {
ChildBloc(this.parentId);
int parentId;
Stream<List<Child>> get items => _controller.asyncMap(...);
Future<List<Child>> _callApi() {
// call endpoint /parents/$parentId/children
}
}
// This bloc created at init state
ParentBloc parentBloc;
// This bloc will be created only after value will
// be selected in the Parent dropdownbutton because
// I need to know `parentId`.
ChildBloc childBloc;
#override
void initState() {
super.initState();
parentBloc = ParentBloc();
}
#override
Widget build(BuildContext context) {
return Row(
children: [
StreamBuilder<List<Parent>>(
stream: parentBloc.items,
builder: (context,snapshot) {
return DropdownButton(
items: snapshot.data.map((item) {
return DropdownButtonItem();
}),
);
}
),
// Content of this widget depends on above one
StreamBuilder<List<Child>>(
stream: childBloc.items,
builder: (context,snapshot) {
return DropdownButton(
items: snapshot.data.map((item) {
return DropdownButtonItem();
}),
);
}
),
// Content of this widget depends on above one
StreamBuilder<List<Grandchild>>(
stream: grandchildBloc.items,
builder: (context,snapshot) {
return ListView(),
);
}
),
]
);
}
Provided you're doing this inside a StatefulWidget, you can use setState inside one of your functions where you update the variables that in turn have to be used to control what is currently displayed in each of your widgets.
It should look something like this (inside your Dropdown):
onChanged: (newValue) {
setState(() {
_currentSelection = newValue;
});
},
Update: after discussion in the comments, here's a working example that I made of how something can be updated based on a value selected inside a dropbox, hope it helps:
import 'package:flutter/material.dart';
class ExampleWidget extends StatefulWidget {
#override
_ExampleWidgetState createState() => _ExampleWidgetState();
}
class _ExampleWidgetState extends State<ExampleWidget> {
List<String> someStringsToSelectFrom = [
'value1',
'value2',
'value3',
];
String selectedValue;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Select something:'),
DropdownButton<String>(
value: selectedValue,
icon: Icon(
Icons.arrow_downward,
color: Colors.deepPurpleAccent,
),
iconSize: 24,
elevation: 16,
style: TextStyle(
fontSize: 30.0,
color: Colors.green,
),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (String newValue) {
setState(() {
selectedValue = newValue;
});
},
items: someStringsToSelectFrom.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
Text('This will update after you selected a value:'),
someStringsToSelectFrom.contains(selectedValue) ? Text(selectedValue + ' was selected') :
Text('Still waiting for user action.'),
],
),
),
);
}
}

Save DropdownButtons and TextField selected Data into a List

I'm trying to create an AlertDialog that will receive a Future-List or a List of the data from the Dropdownbuttons and the TextField that are inside of these Alert. In my App when I call these function for the AlertDialog, there will be 3 DropdownButtons and 1 TextField so the User can select the info that he wants, and then when he presses "OK" from the AlerDialog, the data he selected will be inside of the list, so I can use it with Firestore.
This is my AlertDialog:
Future<List> createAlertDialog(BuildContext context){
return showDialog(context: context, builder: (ctx){
return AlertDialog(
title: Text('Text'),
content: Column(
children: [
DropdownButton(
value: iconNameSelected,
items: iconlistdrop,
hint: Text('Select Icon'),
onChanged: (value) {
iconNameSelected = value;
setState(() {});
},
),
DropdownButton(
value: activelabelSelected,
items: activelistdrop,
hint: Text('Select Active label'),
onChanged: (value1) {
activelabelSelected = value1;
setState(() {});
},
),
DropdownButton(
value: inactivelabelSelected,
items: inactivelistdrop,
hint: Text('Select InActive label'),
onChanged: (value2) {
inactivelabelSelected = value2;
setState(() {});
},
),
TextField(
),
],
),
actions: <Widget>[
MaterialButton(
elevation: 5.0,
child: Text("OK"),
onPressed: (){
final values = [];
Navigator.of(ctx).pop(values);
},
)
],
);
});
}
Here's how I attempted to call it inside my InkWell widget:
createAlertDialog(context).then((value){
printf(value[0]);
printf(value[1]);
printf(value[2]);
printf(value[3]);
}
Here's some extra stuff from the Data I have inserted inside the DropdownButtons:
List<DropdownMenuItem<String>> iconlistdrop = [];
List<DropdownMenuItem<String>> activelistdrop = [];
List<DropdownMenuItem<String>> inactivelistdrop = [];
String iconNameSelected = null;
String activelabelSelected = null;
String inactivelabelSelected = null;
void loadIcon () {
iconlistdrop = [];
iconlistdrop.add(DropdownMenuItem(
child: Text('LightBulb'),
value: 'lightbulbOutline',
));
iconlistdrop.add(DropdownMenuItem(
child: Text('Lock'),
value: 'lock',
));
iconlistdrop.add(DropdownMenuItem(
child: Text('Check'),
value: 'check',
));
}
void activelbl () {
activelistdrop = [];
activelistdrop.add(DropdownMenuItem(
child: Text('On'),
value: 'On',
));
activelistdrop.add(DropdownMenuItem(
child: Text('Locked'),
value: 'Locked',
));
}
void inactivelbl () {
inactivelistdrop = [];
inactivelistdrop.add(DropdownMenuItem(
child: Text('Off'),
value: 'Off',
));
inactivelistdrop.add(DropdownMenuItem(
child: Text('Locked'),
value: 'Unlocked',
));
}
loadIcon();
activelbl();
inactivelbl();
My Class:
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
var temperature;
var humidity;
Future getWeather() async {
http.Response response = await
http.get('http://api.openweathermap.org/data/2.5/weather?
q=Curitiba&units=metric&appid=8c1ce29a0b974e97562564d892cd5a97');
var results = jsonDecode(response.body);
setState(() {
this.temperature = results['main']['temp'];
this.humidity = results['main']['humidity'];
});
}
#override
void initState () {
this.getWeather();
super.initState();
}
#override
Widget build(BuildContext context) {
final AuthService _auth = AuthService();
final user = Provider.of<User>(context);
Future getSubCollection(){
return Firestore.instance.collection('dadosusuarios').document(user.uid).collection('buttons').getDocuments();
}
I would use a map for the values and separate the dialog to another widget and give it a constructor in case you might want it to have initial values.
import 'package:flutter/material.dart';
class MyAlertDialog extends StatefulWidget {
final Map<String, dynamic> initialValues;
const MyAlertDialog({
Key key,
this.initialValues,
}) : super(key: key);
#override
_MyAlertDialogState createState() => _MyAlertDialogState();
}
class _MyAlertDialogState extends State<MyAlertDialog> {
Map<String, dynamic> _values;
TextEditingController _controller;
#override
initState() {
super.initState();
_values = widget.initialValues ??
{'input1': 'One', 'input2': 'Two', 'input3': 'Free', 'input4': 'Four'};
_controller = TextEditingController(text: _values['input4']);
}
#override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Text'),
content: Column(
children: [
DropdownButton(
value: _values['input1'],
items: <String>['One', 'Two', 'Free', 'Four']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
hint: Text('Select Icon'),
onChanged: (value1) {
setState(() {
_values['input1'] = value1;
});
},
),
DropdownButton(
value: _values['input2'],
items: <String>['One', 'Two', 'Free', 'Four']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
hint: Text('Select Active label'),
onChanged: (value2) {
setState(() {
_values['input2'] = value2;
});
},
),
DropdownButton(
value: _values['input3'],
items: <String>['One', 'Two', 'Free', 'Four']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
hint: Text('Select InActive label'),
onChanged: (value3) {
setState(() {
_values['input3'] = value3;
});
},
),
TextField(
controller: _controller,
),
],
),
actions: <Widget>[
MaterialButton(
elevation: 5.0,
child: Text("OK"),
onPressed: () {
_values['input4'] = _controller.text.trim();
Navigator.of(context).pop(_values);
},
)
],
);
}
}
Here i look if there is a value passed from the constructor. If not put some defaults. Update the map with each user input change and finally once the dialog popped return the map. Using map here is better in my opinion and would make pushing the values to Firestore easier.
var result = await showDialog(
context: context,
builder: (ctx) {
return MyAlertDialog(initialValues: /* Your default values if exist*/ );
});
print(result);