Set default value for dropdown button2 in flutter - flutter

Need help with dropdownbutton. I need to set a default value for my dropdown_button2. So that when the page opens, already 1 value is selected, which I can change in the future. Can you please tell me how to implement this function? Previously, I tried options that are already on the Internet, but for some reason it was not possible to implement with my code, perhaps
I made a mistake somewhere. Thanks in advance.
code
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;
#override
Widget build(BuildContext context) {
return Container(
width: widget.width,
decoration: BoxDecoration(
border: Border(
bottom: selectedValue != null
? const BorderSide(
color: constants.Colors.white,
)
: BorderSide.none,
),
),
child: DropdownButtonHideUnderline(
child: DropdownButton2(
underline: DropdownButtonHideUnderline(child: Container()),
hint: Row(
children: [
widget.icon ?? const SizedBox(),
const SizedBox(width: 8),
const Text(
'Select',
style: constants.Styles.bigBookTextStyleWhite,
),
],
),
items: widget.items
.map((item) => DropdownMenuItem<String>(
value: item,
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: constants.Colors.white.withOpacity(0.1),
width: 1,
),
),
),
child: Center(
child: Row(
children: [
if (item == selectedValue)
const SizedBox(
width: 0,
),
Expanded(
child: Text(
item,
style: constants.Styles.smallTextStyleWhite,
),
),
if (item == selectedValue)
const Icon(
Icons.check,
color: constants.Colors.purpleMain,
),
],
),
),
),
))
.toList(),
value: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value as String;
});
},
icon: SvgPicture.asset(constants.Assets.arrowDropdown),
iconSize: 21,
buttonHeight: 27,
itemHeight: 47,
dropdownMaxHeight: 191,
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();
},
),
),
);
}
}

Add the initState method and set your selectedValue there. Here's your code with the initState added so the dropdown defaults to items[0] but you should update it as it fits your use case.
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;
// Add the initState method to your widget
#override
void initState() {
super.initState();
// Set your "default" value here. This example sets it to items[0]
if (widget.items.isNotEmpty) {
selectedValue = widget.items.first;
}
}
#override
Widget build(BuildContext context) {
return Container(
width: widget.width,
decoration: BoxDecoration(
border: Border(
bottom: selectedValue != null
? const BorderSide(
color: constants.Colors.white,
)
: BorderSide.none,
),
),
child: DropdownButtonHideUnderline(
child: DropdownButton2(
underline: DropdownButtonHideUnderline(child: Container()),
hint: Row(
children: [
widget.icon ?? const SizedBox(),
const SizedBox(width: 8),
const Text(
'Select',
style: constants.Styles.bigBookTextStyleWhite,
),
],
),
items: widget.items
.map((item) => DropdownMenuItem<String>(
value: item,
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: constants.Colors.white.withOpacity(0.1),
width: 1,
),
),
),
child: Center(
child: Row(
children: [
if (item == selectedValue)
const SizedBox(
width: 0,
),
Expanded(
child: Text(
item,
style: constants.Styles.smallTextStyleWhite,
),
),
if (item == selectedValue)
const Icon(
Icons.check,
color: constants.Colors.purpleMain,
),
],
),
),
),
))
.toList(),
value: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value as String;
});
},
icon: SvgPicture.asset(constants.Assets.arrowDropdown),
iconSize: 21,
buttonHeight: 27,
itemHeight: 47,
dropdownMaxHeight: 191,
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();
},
),
),
);
}
}
Docs on initState

Related

Flutter TextField selection highlighter controls appear too high

Screenshot of the issue and code in use below, the selection controls are above the textfield for some bizarre reason.
var textField = TextField(
selectionHeightStyle: BoxHeightStyle.max,
scrollPadding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom + 20 * 4),
textInputAction: TextInputAction.done,
keyboardType: TextInputType.numberWithOptions(signed: true, decimal: true),
decoration: InputDecoration(
border: InputBorder.none,
),
controller: textEditingController,
onTap: () {
Future.delayed(const Duration(milliseconds: 800), () {
textEditingController.selectAll();
});
},
onSubmitted: (newText) {
if (newText.length == 0) {
callback(0, true);
} else {
callback(int.parse(newText), true);
}
},
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headline4!.copyWith(
fontWeight: FontWeight.w700,
fontSize: 16.0,
color: WWColors.pinkBrandColor(),
),
);
return Padding(
padding: padding,
child: Container(alignment: Alignment.center, child: textField),
);
In answer to my own question, this in the TextField attributes did the job in my case:
decoration: InputDecoration(
isDense: true, // important line
contentPadding: EdgeInsets.fromLTRB(0, 5, 0, 5),
border: InputBorder.none,
),
Hi you can try create a custom widget for it to make the customisation as you required below is the simple example for the mentioned implementation.
class CounterWidget extends StatefulWidget {
final double width;
final double height;
final double spaceWidth;
final Color controlColor;
final Color valueColor;
final Function(int count) callback;
const CounterWidget({
Key? key,
required this.title,
required this.callback,
required this.controlColor,
required this.valueColor,
this.width = 50,
this.height = 30,
this.spaceWidth = 5,
}) : super(key: key);
final String title;
#override
State<CounterWidget> createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int count = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Row(
children: [
//Incrementor
InkWell(
onTap: () {
setState(() {
count++;
//Callback method to expose the count to the higher hier archy.
widget.callback(count);
});
},
child: Container(
decoration: BoxDecoration(
color: widget.controlColor,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(widget.height / 0.1),
bottomLeft: Radius.circular(widget.height / 0.1),
),
),
child: const Center(
child: Icon(
Icons.add,
color: Colors.white,
),
),
width: widget.width,
height: widget.height,
),
),
SizedBox(width: widget.spaceWidth),
Container(
color: widget.valueColor,
width: widget.width,
height: widget.height,
child: Center(
child: Text(
count.toString(),
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
),
),
SizedBox(width: widget.spaceWidth),
InkWell(
onTap: () {
if (count > 0) {
setState(() {
count--;
widget.callback(count);
});
}
},
child: Container(
width: widget.width,
height: widget.height,
decoration: BoxDecoration(
color: widget.controlColor,
borderRadius: BorderRadius.only(
topRight: Radius.circular(widget.height / 0.1),
bottomRight: Radius.circular(widget.height / 0.1),
),
),
child: const Center(
child: Icon(
Icons.remove,
color: Colors.white,
),
),
),
),
],
),
);
}
}

setState not updating the value in the screen using Flutter desktop

So I'm trying to update the value of the drop down list using the setState, but when I select a value from the list, the value on the screen won't be able to change
import 'package:demo_app_admin/Custom/custom_Font.dart';
import 'package:flutter/material.dart';
import '/Custom/Custom_Raised_Bottun.dart';
import '/Custom/Header.dart';
import '/Custom/inputField.dart';
class LoginView extends StatefulWidget {
#override
_LoginViewState createState() => _LoginViewState();
}
class _LoginViewState extends State<LoginView> {
#override
Widget build(BuildContext context) {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final isKeyboard = MediaQuery.of(context).viewInsets.bottom != 0;
String _dropdownvalue = "Global admin";
List<String> _items = <String> ["Global admin", "Institution admin"];
return Scaffold(
body: Container(
width: double.infinity,
decoration: BoxDecoration(
gradient: LinearGradient(begin: Alignment.topCenter, colors: [
Colors.teal[700]!,
Colors.teal[200]!,
Colors.teal[400]!
]),
),
child: Column(
children: <Widget>[
const SizedBox(
height: 80,
),
if (!isKeyboard)
Header(
padding: const EdgeInsets.all(20),
crossAxisAlignment: CrossAxisAlignment.start,
head: "Welcome",
headTextStyle:
const TextStyle(color: Colors.white, fontSize: 40),
sizedBoxHeight: 10,
subtitle: "Sign In to Your Admin Account",
subtitleTextStyle:
const TextStyle(color: Colors.white, fontSize: 18),
),
Expanded(
child: Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(60),
topRight: Radius.circular(60),
)),
child: Padding(
padding: const EdgeInsets.all(30),
child: SingleChildScrollView(
reverse: true,
padding: EdgeInsets.all(32),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
const SizedBox(
height: 40,
),
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10)),
child: Column(
children: <Widget>[
InputField(
labelText: 'Email',
padding: EdgeInsets.all(10),
borderSide: BorderSide(color: Colors.grey),
hintText: "Enter your email",
color: Colors.grey,
inputBorder: InputBorder.none,
obscureText: false,
enableSuggestion: true,
autoCorrect: true,
onSaved: (value) {},
// (value){controller.email = value!;},
validator: (value) {
if (value == null) {
print("ERROR");
}
},
),
InputField(
labelText: 'Password',
padding: EdgeInsets.all(10),
borderSide: BorderSide(color: Colors.grey),
hintText: "Enter your password",
color: Colors.grey,
inputBorder: InputBorder.none,
obscureText: true,
enableSuggestion: false,
autoCorrect: false,
onSaved: (value) {},
// (value){ controller.password = value!;},
validator: (value) {
if (value == null) {
print("ERROR");
}
},
),
],
),
),
const SizedBox(
height: 40,
),
here is the issue
DropdownButton<String>(
value: _dropdownvalue,
icon: Icon(Icons.keyboard_arrow_down),
items: _items.map((String _items) {
return DropdownMenuItem<String>(
value: _items,
child: CustomFont(text: _items),
);
}).toList(),
onChanged: (value) {
setState(() => _dropdownvalue = value!);
}),
const SizedBox(
height: 40,
),
CustomRaisedButton(
width: 200,
height: 50.0,
margin: const EdgeInsets.symmetric(horizontal: 50),
color: Colors.teal.shade500,
borderRadius: BorderRadius.circular(10),
text: "LOGIN",
textColor: Colors.white,
fontSize: 17,
fontWeight: FontWeight.bold,
function: () {}
// {
// _formKey.currentState?.save();
// if(_formKey.currentState?.validate() !=null){
// controller.signInWithEmailAndPassword();
// }
// },
),
SizedBox(
height: 10,
),
],
),
),
),
),
))
],
),
),
);
}
}
The issue is here, you are declaring variables inside build. Therefore, variables get reset to default value on every build. Means setState.
Declare variables outside the build method.
class _LoginViewState extends State<LoginView> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
String _dropdownvalue = "Global admin";
List<String> _items = <String>["Global admin", "Institution admin"];
#override
Widget build(BuildContext context) {
final isKeyboard = MediaQuery.of(context).viewInsets.bottom != 0;
return Scaffold(
More about StatefulWidget.

How to get the index of each element in a list flutter?

I ran into a problem. I have a Checkbox in the value method, I need to specify _isChecked[index]. But I have an error on the word index. I understand why the error is because I don't get the index of each element, I don't have these given. Do I need to iterate through all the elements of the list to solve? Or how can I get all index elements?
code
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 isChecked = false;
List<bool> _isChecked = [];
#override
void initState() {
super.initState();
if (widget.items.isNotEmpty) {
selectedValue = widget.items[1];
}
_isChecked = List<bool>.filled(widget.items.length, false);
}
#override
Widget build(BuildContext context) {
return SizedBox(
width: widget.width,
child: DropdownButtonHideUnderline(
child: DropdownButton2(
items: widget.items
.map((item) => DropdownMenuItem<String>(
value: item,
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: constants.Colors.white.withOpacity(0.1),
width: 1,
),
),
),
child: Center(
child: Row(
children: [
if (item == selectedValue)
const SizedBox(
width: 0,
),
Expanded(
child: Text(
item,
style: constants.Styles.smallTextStyleWhite,
),
),
Checkbox(
value: _isChecked[index],
onChanged: (val) {
setState(() {
_isChecked[index] = val!;
});
},
)
],
),
),
),
))
.toList(),
value: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value as String;
});
},
icon: SvgPicture.asset(constants.Assets.arrowDropdown),
iconSize: 21,
buttonHeight: 27,
itemHeight: 47,
dropdownMaxHeight: 191,
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();
},
),
),
);
}
}
List
final List<String> carList = const [
"All EV's",
'Main EV',
'<EV2>',
];
you can convert the list to a map and iterate on its keys, which will be the indices of the elements
widget.items.asMap().keys.map((index) {
return Container(
child: widget.items[index];
);
}).toList(),

Combine two similar classes into one class in flutter

I have two dropdownbutton, they differ in that one has checkboxes and the other doesn't. The code is similar and I think it would be better to put everything in one class. I tried to do this, the dropdownbutton with the checkbox did not work correctly for me. Can you tell me if these 2 codes can be placed in one class? And how to do it right?
code_1
class DropdownWidget extends StatefulWidget {
List<String> items;
SvgPicture? icon;
double width;
bool isCheckbox;
DropdownWidget(
{Key? key,
required this.items,
required this.icon,
required this.width,
this.isCheckbox = false})
: super(key: key);
#override
State<DropdownWidget> createState() => _DropdownWidgetState();
}
class _DropdownWidgetState extends State<DropdownWidget> {
String? selectedValue;
bool isChecked = false;
#override
void initState() {
super.initState();
if (widget.items.isNotEmpty) {
selectedValue = widget.items[1];
}
}
#override
Widget build(BuildContext context) {
return SizedBox(
width: widget.width,
child: DropdownButtonHideUnderline(
child: DropdownButton2(
items: widget.items
.map(
(item) => DropdownMenuItem<String>(
value: item,
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: constants.Colors.white.withOpacity(0.1),
width: 1,
),
),
),
child: Center(
child: Row(
children: [
if (item == selectedValue)
const SizedBox(
width: 0,
),
Expanded(
child: Text(
item,
style: constants.Styles.smallTextStyleWhite,
),
),
if (item == selectedValue)
const Icon(
Icons.check,
color: constants.Colors.purpleMain,
),
],
),
),
),
),
)
.toList(),
value: selectedValue,
onChanged: (value) {
setState(() {
selectedValue = value as String;
});
},
icon: SvgPicture.asset(constants.Assets.arrowDropdown),
iconSize: 21,
buttonHeight: 27,
itemHeight: 47,
dropdownMaxHeight: 191,
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();
},
),
),
);
}
}
code_2
class CheckboxDropdown extends StatefulWidget {
List<String> items;
SvgPicture? icon;
double width;
CheckboxDropdown({
Key? key,
required this.items,
this.icon,
required this.width,
}) : super(key: key);
#override
State<CheckboxDropdown> createState() => _CheckboxDropdown();
}
class _CheckboxDropdown extends State<CheckboxDropdown> {
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: 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: Row(
children: [
SvgPicture.asset(constants.Assets.carDropdown),
const SizedBox(width: 8),
_selectedTitles.length > 1
? const Text('Selecte EV',
style: constants.Styles.xSmallLtStdTextStyleWhite)
: 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();
},
),
),
);
}
}
Create a class such as MultiDropDownBox and pass a required bool in constructor such as isCheckBox . Return the required widget as per bool value.
Example code snippet
class MultiDropdownBox extends StatefulWidget {
final bool isCheckbox;
MultiDropdownBox(
{Key? key,
required this.isCheckBox,
})
: super(key: key);
#override
State<MultiDropdownBox> createState() => _MultiDropdownBoxState();
}
class _MultiDropdownBoxState extends State<MultiDropdownBox> {
bool isChecked = widget.isChecked;
#override
Widget build(BuildContext context) {
if(isChecked){return CheckboxDropdown()};
else{return DropdownWidget()}
}
Upvote if it helped :)

Passing data between screen but using extracted dropdown button widget

First of all, here is my condition. I'm trying to pass all the data that were filled in Dropdownbutton and Date & Time picker at the first screen (left picture) to the second screen(right picture). The problem is, I extracted the DropDownButton widget to another class, and I don't understand how to implement it.
Before that, this is the first screen Code :
class InformationDetail extends StatefulWidget {
static const String id = 'InformationDetail';
#override
_InformationDetailState createState() => _InformationDetailState();
}
class _InformationDetailState extends State<InformationDetail> {
String addressText, addNotes;
DateTime selectedDate = DateTime.now();
TimeOfDay selectedTime = TimeOfDay.now();
Future<Null> _selectDate(BuildContext context) async {
final DateTime picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(2015, 8),
lastDate: DateTime(2101));
if (picked != null && picked != selectedDate)
setState(() {
selectedDate = picked;
});
}
Future<Null> _selectTime(BuildContext context) async {
final TimeOfDay picked = await showTimePicker(
context: context,
initialTime: selectedTime,
);
if (picked != null && picked != selectedTime)
setState(() {
selectedTime = picked;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListView(
children: <Widget>[
Container(
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.fromLTRB(25.0, 68.0, 70.0, 26.0),
child: Text(
'Information Detail',
style: TextStyle(fontSize: 35.0),
),
),
Column(
// Wrap Column
children: <Widget>[
Column(
children: <Widget>[
TitleName(
titleText: 'Grooming Type',
infoIcon: Icons.info,
),
MenuDropDown(
dropdownText: 'Grooming Type...',
type: "groomingType",
),
TitleName(
titleText: 'Cat Breeds',
),
MenuDropDown(
dropdownText: 'Cat Breeds...',
type: "catBreeds",
),
TitleName(
titleText: 'Cat Size',
infoIcon: Icons.info,
),
MenuDropDown(
dropdownText: 'Cat Size...',
type: "catSize",
),
TitleName(
titleText: 'Add-On Services',
),
MenuDropDown(
dropdownText: 'Add - On Services...',
type: "addOnServices",
),
TitleName(
titleText: 'Reservation Date',
),
Row(
children: <Widget>[
Container(
width: 130,
height: 30,
margin: EdgeInsets.fromLTRB(50.0, 0, 62, 0),
child: RaisedButton(
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 6,
child: Text(
'Choose Date',
style: TextStyle(
fontSize: 12.0,
),
),
onPressed: () => _selectDate(context),
),
),
Text("${selectedDate.toLocal()}".split(' ')[0]),
],
),
TitleName(
titleText: 'Reservation Time',
),
Row(
children: <Widget>[
Container(
width: 130,
height: 30,
margin: EdgeInsets.fromLTRB(50.0, 0, 62, 0),
decoration: BoxDecoration(),
child: RaisedButton(
color: Colors.white,
child: Text(
'Choose Time',
style: TextStyle(
fontSize: 12.0,
),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 6,
onPressed: () => _selectTime(context),
),
),
Text("${selectedTime.toString()}".split(' ')[0]),
],
),
TitleName(
titleText: 'Pick Up Address',
),
Container(
width: 320,
height: 40,
child: TextFormField(
maxLines: null,
minLines: null,
expands: true,
decoration: InputDecoration(
contentPadding:
EdgeInsets.fromLTRB(35.0, 10.0, 0, 10.0),
hintText: 'Address Here...',
hintStyle: TextStyle(
fontSize: 15.0,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
),
),
onChanged: (value) {
addressText = value;
},
),
),
TitleName(
titleText: 'Additional Notes',
infoIcon: Icons.info,
),
Container(
width: 320,
child: TextFormField(
maxLines: 4,
decoration: InputDecoration(
contentPadding:
EdgeInsets.fromLTRB(35.0, 10.0, 0, 10.0),
hintText: 'E.g. ',
hintStyle: TextStyle(
fontSize: 15.0,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
),
),
onChanged: (value) {
addNotes = value;
},
),
),
Container(
margin: EdgeInsets.fromLTRB(0, 15.0, 0, 0),
width: 75.0,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.rectangle,
border: Border.all(
color: Colors.black,
),
borderRadius: BorderRadius.circular(12.0),
),
child: IconButton(
icon: Icon(Icons.arrow_forward),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ConfirmationOrder(
addressText: addressText,
addNotes: addNotes,
)));
}),
),
],
),
],
),
],
),
),
],
)),
);
}
}
Below the first picture, there's a button to navigate to the second screen.
And here is the class where I extracted DropDownButton :
class MenuDropDown extends StatefulWidget {
final String dropdownText;
final String type;
MenuDropDown({this.dropdownText, this.type});
#override
_MenuDropDownState createState() => _MenuDropDownState();
}
class _MenuDropDownState extends State<MenuDropDown> {
String selectedItem;
List<String> dropdownItems = [];
List<String> groomingTypeList = ['Basic Grooming', 'Full Grooming'];
List<String> catBreedsList = [
'Persia',
'Anggora',
'Domestic',
'Maine Coon',
'Russian Blue',
'Slamese',
'Munchkin',
'Ragdoll',
'Scottish Fold',
];
List<String> catSizeList = [
'Small Size',
'Medium Size',
'Large Size',
'Extra Large Size',
];
List<String> addOnServicesList = [
'Spa & Massage',
'Shaving Hair / Styling',
'Injection Vitamis Skin & Coat',
'Cleaning Pet House and Environment',
'Fur Tangled Treatment',
];
List<String> getListBasedOnName(String value) {
print(value);
switch (value) {
case "groomingType":
return groomingTypeList;
break;
case "catBreeds":
return catBreedsList;
break;
case "catSize":
return catSizeList;
break;
case "addOnServices":
return addOnServicesList;
break;
}
return null;
}
#override
void initState() {
super.initState();
print(widget.type);
dropdownItems = getListBasedOnName(widget.type);
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(0, 8.0, 0, 10.0),
child: Container(
width: 325.0,
height: 50.0,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black45,
offset: Offset(2.5, 5.5),
blurRadius: 5.0,
)
],
borderRadius: BorderRadius.circular(8),
color: Colors.white,
),
child: DropdownButtonHideUnderline(
child: DropdownButton(
value: selectedItem,
hint: Padding(
padding: const EdgeInsets.fromLTRB(22.0, 0, 0, 0),
child: Text(
widget.dropdownText,
style: TextStyle(),
),
),
items: dropdownItems.map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (value) {
setState(() {
selectedItem = value;
});
}),
),
),
);
}
}
I really got confused because the onChanged function in DropDownButton already used. I barely manage to do the normal pass data from the text widget. But from the Dropdownbutton and the date & time picker, I have no idea how to do it.
Is there any way to get the data from the first screen, because at the moment I still haven't learned about state management or Bloc. And the code still messy I haven't done the refactoring yet. I really Hope you can help with the solution, Thank you!
First, for the MenuDropDown, you're going to want to do a sort of extension for the onChanged method. Add a VoidCallback parameter to the widget's constructor like so:
typedef OnChangeCallback = void Function(dynamic value);
class MenuDropDown extends StatefulWidget {
final String dropdownText;
final String type;
final OnChangeCallback onChanged;
MenuDropDown({this.dropdownText, this.type, this.onChanged});
#override
_MenuDropDownState createState() => _MenuDropDownState();
}
and in the state, call that method as a part of DropdownButton's native onChanged callback:
onChanged: (value) {
setState(() {
selectedItem = value;
});
widget.onChanged(value);
}
And in _InformationDetailState you'll store the currently selected item for each input field and pass an onChanged function that updates the respective field for each input:
String catSize; //Declare at the top of _InformationDetailState
...
MenuDropDown(
dropdownText: 'Cat Size...',
type: "catSize",
onChanged: (value) {
catSize = value;
}
),
Now to pass the data to the next screen. It's never really absolutely necessary to use any kind of state management in your app and I've found that many people use it unnecessarily. In your case, it's absolutely not necessary for just passing data to a single other widget. You're already passing the addressText and addNotes correctly. Just extend this for each parameter you need to show on the confirmation screen. Alternatively, you could store all of the fields in a single Map instead of having a variable for each field and pass that Map to the confirmation page.