Related
am taking date of birth from users while registering, users click on the form field so date picker shows and they choose their date of birth, the problem is for example user chooses "15-October-1996", the months always show as "00" like this "15-00-1996" here is the "DateTimeField()" code:
final birthDateField = DateTimeField(
controller: dateController,
format: DateFormat("dd-mm-yyyy"),
onShowPicker: (context, currentValue) async {
final date = await showDatePicker(
context: context,
initialDate: currentValue ?? DateTime.now(),
firstDate: DateTime(1920),
lastDate: DateTime(2030));
return date;
},
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
labelText: 'تاريخ الميلاد',
prefixIcon: Icon(Icons.calendar_month),
),
);
and i rendered the fields inside a Scaffold widget as follows:
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.purple,
),
onPressed: () {
Navigator.of(context).pop();
},
),
),
body: Center(
//Use the SingleChildScrollView as a wrapper to ensure scrolling in case scorrling is needed.
child: SingleChildScrollView(
//wrap the elements with Container to provide flexibility in designing the elements.
child: Container(
color: Colors.white,
//use the form as a container of the input fields as it is a login form.
child: Padding(
padding: const EdgeInsets.all(36.0),
child: Form(
//give the form wrapper the key value to tell flutter that this is the form design for your form functions.
key: _formKey,
//use the column to show the elements in vertical array.
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
//Use children property inside the column to specify list of widgets
children: [
birthDateField,
SizedBox(
height: 20,
),
signUpButton,
]),
),
),
),
),
),
);
am using a controller to update values and send to database, i also imported all the necessary packages, so am not sure what am missing i would be thankful for any help.
Try changing the dataformat with format: DateFormat("dd-MM-yyyy"),
change your formatter to "dd-MM-yyyy":
final birthDateField = DateTimeField(
controller: dateController,
format: DateFormat("dd-MM-yyyy"), //<- change this
onShowPicker: (context, currentValue) async {
final date = await showDatePicker(
context: context,
initialDate: currentValue ?? DateTime.now(),
firstDate: DateTime(1920),
lastDate: DateTime(2030));
return date;
},
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
labelText: 'تاريخ الميلاد',
prefixIcon: Icon(Icons.calendar_month),
),
);
```
I am using List items for DropdownButton widget in StatefulBuilder. When I select any item on DropdownButton its not updating at this stage. But when I close the showModalBottomSheet widget and open again its updating. How can I fix this? Thanks for help.
This is my menu code for items
List<DropdownMenuItem<String>> tur = [];
void kategoritur(){
tur = [];
tur.add(new DropdownMenuItem(
child: Row(
children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/g.png'),
fit: BoxFit.fitWidth,
),
),
height: 50, width: 50,
),
SizedBox(width: 30,),
new Text("Şırınga"),
],
),
value: "Siringa",)
);
tur.add(new DropdownMenuItem(
child: Row(
children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/t.png'),
fit: BoxFit.fitWidth,
),
),
height: 50, width: 50,
),
SizedBox(width: 30,),
new Text("Hap"),
],
),
value: "Hap",)
);
tur.add(new DropdownMenuItem(
child: Row(
children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/f.png'),
fit: BoxFit.fitWidth,
),
),
height: 50, width: 50,
),
SizedBox(width: 30,),
new Text("Şişe"),
],
),
value: "Sise",)
);
tur.add(new DropdownMenuItem(
child: Row(
children: <Widget>[
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/e.png'),
fit: BoxFit.fitWidth,
),
),
height: 50, width: 50,
),
SizedBox(width: 30,),
new Text("Damla"),
],
),
value: "Damla",)
);
}
This is my main code
showModalBottomSheet(
useRootNavigator: true,
context: context,
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(24),
),
),
builder: (context) {
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: StatefulBuilder(
builder: (context, setModalState) {
return Container(
padding: const EdgeInsets.all(32),
child: Column(
children: [
FlatButton(
onPressed: () async {
var selectedTime =
await showTimePicker(
builder: (BuildContext context, Widget child) {
return MediaQuery(
data: MediaQuery.of(context)
.copyWith(alwaysUse24HourFormat: false),
child: Theme(
data: ThemeData.dark().copyWith(
colorScheme: ColorScheme.dark(
primary: Color(0xFF52b788),
onPrimary: Color(0xFF52b788),
surface: Colors.white,
onSurface: Color(0xFF52b788),
),
dialogBackgroundColor:
Color(0xFF52b788),
),
child: child),
);
},
context: context,
initialTime:
TimeOfDay.now(),
);
if (selectedTime != null) {
final now = DateTime.now();
var selectedDateTime =
DateTime(
now.year,
now.month,
now.day,
selectedTime.hour,
selectedTime
.minute);
_alarmTime =
selectedDateTime;
setModalState(() {
_alarmTimeString =
DateFormat('HH:mm')
.format(
selectedDateTime);
});
}
},
child: Text(
_alarmTimeString,
style:
TextStyle(fontSize: 32),
),
),
Container(
margin: EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.black38,
borderRadius: BorderRadius.circular(18)
),
width: _width,
padding: EdgeInsets.fromLTRB(14, 0, 14, 0),
child: DropdownButton(
style: GoogleFonts.montserrat(
color: Colors.white,
fontSize: 16,
textStyle: TextStyle(fontWeight:
FontWeight.w300)),
dropdownColor: Colors.cyan[700],
underline: SizedBox.shrink(),
items: tur,
onChanged: (value){
turdata = value;
setState(() {
});
},
hint: new Text("İlaç Türü", textAlign:
TextAlign.center
,
style: GoogleFonts.montserrat(
color: Colors.white,
fontSize: 16,
textStyle: TextStyle(fontWeight:
FontWeight.w300)),
),
value: turdata,
),
),
SizedBox(height: 20,),
FloatingActionButton.extended(
backgroundColor: Color(0xFF52b788),
onPressed: onSaveAlarm,
icon: Icon(Icons.alarm),
label: Text('Save'),
),
],
),
);
},
),
);
},
);
i made a custom class of dropdown you can customize this in your own way
import 'package:flutter/material.dart';
import 'package:rio/Utils/utils.dart';
import 'package:rio/widgets/widgets.dart';
import 'package:rio/generated/l10n.dart';
import 'package:responsive_flutter/responsive_flutter.dart';
import 'color.dart';
// ignore: must_be_immutable
class DropDownClass extends StatelessWidget {
var _hint;
var _val;
double _fontSize;
List _list = new List();
bool _icon;
bool _border;
Color _underLineColor, _dropDownColor, _textColor;
List get list => _list;
dynamic Function(dynamic) _listener;
DropDownClass({List list,
var hint,
Color underLineColor,
Color dropDownColor,
Color textColor,
double fontSize,
bool icon,
var val,
int type,
bool border = true,
dynamic Function(dynamic) listener,})
: _list = list,
_hint = hint,
_underLineColor = underLineColor,
_dropDownColor = dropDownColor,
_textColor = textColor,
_icon = icon,
_val = val,
_fontSize = fontSize,
_border = border,
_listener = listener;
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
Utils.selectedValue = null;
},
child: DropdownButtonHideUnderline(
child: DropdownButtonFormField<String>(
value: _val,
dropdownColor: _dropDownColor ?? CustomColors.white,
decoration:_border == true? InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: _underLineColor ?? Theme
.of(context)
.hintColor,
width: 1.0,
),
)
):InputDecoration(
border: InputBorder.none,
fillColor: Theme.of(context).cardColor,
filled: true),
style: robotoStyle(context,
color: _textColor ??
Theme
.of(context)
.primaryTextTheme
.bodyText1
.color,
fontWeight: FontWeight.w400,
fontSize: _icon == null || _icon == false
? ResponsiveFlutter.of(context).fontSize(_fontSize??1.5)
: ResponsiveFlutter.of(context).fontSize(_fontSize??1.5)),
isExpanded: true,
icon: _icon == null || _icon == false
? null
: Icon(
Icons.keyboard_arrow_down,
color: CustomColors.appBarTextColor,
),
hint: Text(_hint,
style: robotoStyle(context,
color: _icon == null || _icon == false
? Theme
.of(context)
.hintColor
: Theme
.of(context)
.textSelectionColor,
fontWeight: FontWeight.w400,
fontSize: _icon == null || _icon == false
? ResponsiveFlutter.of(context)
.fontSize(_fontSize??1.75)
: ResponsiveFlutter.of(context).fontSize(_fontSize??1.5))),
items: list.map((item) {
return DropdownMenuItem<String>(
value: item,
child: new Text(item,
style: robotoStyle(context,
color: _textColor ?? CustomColors.dropDownTextColor,
fontWeight: FontWeight.w400,
fontSize: _icon == null || _icon == false
? ResponsiveFlutter.of(context)
.fontSize(_fontSize??1.75)
: ResponsiveFlutter.of(context).fontSize(_fontSize??1.5))),
);
}).toList(),
onChanged: (value) {
_val = value;
if (_listener != null) _listener.call(value);
if (_icon == true) {
Utils.selectedValue = value;
S.load(Locale(value));
Utils.preferences.setString("lang", value);
}
// return val;
},
),
),
);
}
}
Hello Friends,
Can someone guide me to do this kind of UI making in flutter?
Thanks in advance...
I hope this code will work for you. You just need to add your datepicker logic on this textfield.
body: Container(
child: Row(
children: [
Container(
width: 5,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Start Date"),
GestureDetector(
onTap: () {
selectDate(context);
},
child: AbsorbPointer(
absorbing: true,
child: TextFormField(
style: TextStyle(color: Colors.black),
controller: startdata,
decoration: InputDecoration(
suffixIcon:
Icon(Icons.calendar_today, color: Colors.blue)),
),
),
)
],
)),
Container(
width: 5,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("End Date"),
GestureDetector(
onTap: () {
// Your second date picker logic
},
child: AbsorbPointer(
absorbing: true,
child: TextFormField(
controller: enddata,
decoration: InputDecoration(
suffixIcon:
Icon(Icons.calendar_today, color: Colors.blue)),
),
),
)
],
)),
Container(
width: 5,
),
],
)),
Select Date
TextEditingController startdata = new TextEditingController();
TextEditingController enddata = new TextEditingController();
DateTime selectedDate = DateTime.now();
var myFormat = DateFormat('yyyy-MM-dd');
Future selectDate(BuildContext context) async {
final DateTime picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: selectedDate,
lastDate: DateTime(2101),
builder: (BuildContext context, Widget child) {
return Theme(
data: ThemeData.light().copyWith(
primaryColor: WidgetColors.buttonColor,
accentColor: WidgetColors.buttonColor,
colorScheme: ColorScheme.light(primary: WidgetColors.buttonColor),
buttonTheme: ButtonThemeData(textTheme: ButtonTextTheme.primary),
),
child: child,
);
},
);
if (picked != null) {
setState(() {
selectedDate = picked;
startdata = TextEditingController(text: myFormat.format(picked),);
});
} else {}
}
Try this
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Start Date", style: TextStyle(
color: Colors.blueGrey,
),),
SizedBox(height: 15.0,),
GestureDetector(
onTap: () {
// Show You Date Picker Here
},
child: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("YourDate e.g May 7, 2018"),
Icon(Icons.calendar_today, color: Colors.blue,),
],
),
),
)
],
),
),
SizedBox(width: 10.0,),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("End Date", style: TextStyle(
color: Colors.blueGrey,
),),
SizedBox(height: 15.0,),
GestureDetector(
onTap: () {
// Show You Date Picker Here
},
child: Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("YourDate e.g May 8, 2018"),
Icon(Icons.calendar_today, color: Colors.blue,),
],
),
),
),
],
),
),
],
)
I have a generic TextFieldWidget class I use for all my Flutter projects, which is really useful and can answer your question.
enum TextFieldType {
Password,
Email,
Text,
Picker,
}
class TextFieldWidget extends StatefulWidget {
final TextEditingController controller;
final FocusNode focusNode;
final Key key;
final String errorText;
final String hintText;
final Color errorBorderColor;
final bool autofocus;
final bool isEnabled;
final Function onChanged;
final Function onTap;
final TextFieldType textFieldType;
final TextCapitalization textCapitalization;
final Widget suffixIcon;
TextFieldWidget({
this.controller,
this.focusNode,
this.key,
this.errorText,
this.hintText,
this.errorBorderColor,
this.autofocus = false,
this.isEnabled = true,
this.onChanged,
this.onTap,
this.textFieldType = TextFieldType.Text,
this.textCapitalization = TextCapitalization.none,
this.suffixIcon,
});
#override
State createState() => _TextFieldWidgetState();
}
class _TextFieldWidgetState extends State<TextFieldWidget> {
final double _borderSideWidth = 0.5;
bool _shouldObscureText = true;
#override
Widget build(BuildContext context) {
return TextField(
style: TextStyle(
color: !widget.isEnabled ? ThemeColors.text.tertiaryLight : null,
fontSize: ThemeFonts.size.textFieldText,
),
enabled: widget.isEnabled,
controller: this.widget.controller,
focusNode: this.widget.focusNode,
decoration: _getTextFieldDecoration(),
autofocus: this.widget.autofocus,
obscureText: _shouldTextBeObscured(),
onChanged: this.widget.onChanged,
onTap: this.widget.onTap,
keyboardType: _getKeyboardType(),
textCapitalization: this.widget.textCapitalization,
enableInteractiveSelection: this.widget.textFieldType != TextFieldType.Picker,
);
}
InputDecoration _getTextFieldDecoration() {
return InputDecoration(
suffixIcon: _getSuffixIcon(),
labelText: widget.hintText,
labelStyle: TextStyle(color: ThemeColors.text.tertiary),
errorText: widget.errorText,
errorStyle: TextStyle(
color: widget.isEnabled ? ThemeColors.text.tertiary : ThemeColors.text.tertiaryLight,
fontSize: ThemeFonts.size.textFieldPlaceholder,
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: ThemeColors.text.tertiary,
width: _borderSideWidth,
),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: ThemeColors.border.secondary,
width: _borderSideWidth,
),
),
focusedErrorBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: ThemeColors.text.tertiary,
width: _borderSideWidth,
),
),
errorBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: this.widget.errorBorderColor ?? ThemeColors.text.tertiary,
width: _borderSideWidth,
),
),
);
}
TextInputType _getKeyboardType() {
switch (this.widget.textFieldType) {
case TextFieldType.Email:
return TextInputType.emailAddress;
default:
return TextInputType.text;
}
}
Widget _getSuffixIcon() {
switch (this.widget.textFieldType) {
case TextFieldType.Picker:
return Icon(Icons.unfold_more);
case TextFieldType.Password:
return IconButton(
icon: Icon(Icons.remove_red_eye),
color: _shouldObscureText ? ThemeColors.icon.secondaryLight : ThemeColors.icon.secondary,
onPressed: () {
setState(() {
_shouldObscureText = !_shouldObscureText;
});
},
);
case TextFieldType.Text:
return this.widget.suffixIcon != null ? this.widget.suffixIcon : null;
default:
return null;
}
}
bool _shouldTextBeObscured() {
if (widget.textFieldType == TextFieldType.Password) {
return _shouldObscureText;
}
return false;
}
}
And when you want to use it for Date picking just call it like this:
TextFieldWidget(
focusNode: _dateFocusNode,
controller: _dateTextController,
textFieldType: TextFieldType.Picker,
hintText: 'Date of birth',
onTap: () {
if (FocusScope.of(context).hasFocus) {
FocusScope.of(context).requestFocus(FocusNode());
}
// Call code that opens date picker here
},
),
Keep in mind this TextField provides more options than what you need right now, but if you plan on having error handling, different UI colours for those cases, different UI for password, email and other input this will be of great help.
I am trying to let users add dates to a list in my app and I have managed to create my text field as well as the date selector. I am struggling to set the value of the selected date to a variable and populate the text field when a user picks one. I have tried accessing the _date value from _selectDate but still nothing populates my TextField.
Here is my code:
class DatesToRemember extends StatefulWidget {
#override
_DatesToRememberState createState() => _DatesToRememberState();
}
class _DatesToRememberState extends State<DatesToRemember> {
DateTime selectedDate = DateTime.now();
TextEditingController _date = new TextEditingController();
Future<Null> _selectDate(BuildContext context) async {
DateFormat formatter =
DateFormat('dd/MM/yyyy'); //specifies day/month/year format
final DateTime picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1901, 1),
builder: (BuildContext context, Widget child) {
return Theme(
data: ThemeData.light().copyWith(
colorScheme: ColorScheme.light(
primary: kPrimaryColor,
onPrimary: Colors.black,
),
buttonTheme: ButtonThemeData(
colorScheme: Theme.of(context)
.colorScheme
.copyWith(primary: Colors.black),
),
),
child: child,
);
},
lastDate: DateTime(2100));
if (picked != null && picked != selectedDate)
setState(() {
selectedDate = picked;
_date.value = TextEditingValue(
text: formatter.format(
picked));//Use formatter to format selected date and assign to text field
});
return _date;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: GestureDetector(
onTap: () => Navigator.pop(context),
child: Icon(Icons.arrow_back)),
title: Text('Dates to Remember'),
),
backgroundColor: Colors.white,
body: Center(
child: Column(children: [
SizedBox(
height: 10.0,
),
Container(
width: MediaQuery.of(context).size.width * 0.8,
child: Text(
"It can be difficult to ",
style: TextStyle(fontFamily: FontNameDefault),
),
),
SizedBox(
height: 50.0,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Align(
alignment: Alignment.centerRight,
child: FloatingActionButton(
backgroundColor: kPrimaryColor,
child: Icon(Icons.add),
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Add occasion'),
content: Container(
height: 150.0,
child: Column(
children: [
TextField(
onChanged: (String value) {
input = value;
},
decoration: InputDecoration(
hintText: 'Occasion Title'
),
),
TextField(
decoration: InputDecoration(
hintText: 'Pick Date'
),
onTap: () => _selectDate(context),
),
FlatButton(
child: Text('Add'),
onPressed: () {
setState(() {
occasions.add(input);
});
Navigator.of(context).pop();
},
),
],
),
),
);
});
}),
),
),
Container(
height: MediaQuery.of(context).size.height * 0.6,
width: MediaQuery.of(context).size.width * 0.9,
decoration: BoxDecoration(
border: Border.all(color: Colors.black26)
),
child:
occasions.isEmpty? Center(child: Text('Add an occasion', style: TextStyle(
color: Colors.black
),)) : ListView.builder(
itemCount: occasions.length,
itemBuilder: (BuildContext context, int index) {
return
Dismissible(
direction: DismissDirection.endToStart,
onDismissed: (direction) {
occasions.removeAt(index);
Scaffold.of(context).showSnackBar(new SnackBar(
content: Text('Occasion Removed'),
duration: Duration(seconds: 5),
));
},
key: UniqueKey(),
child: Card(
elevation: 8.0,
margin: EdgeInsets.all(8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
child: ListTile(
title: Text(occasions[index]),
trailing: IconButton(
icon: Icon(
Icons.delete,
color: Colors.red,
),
onPressed: () {
setState(() {
occasions.removeAt(index);
Scaffold.of(context).showSnackBar(new SnackBar(
content: Text('Occasion Removed'),
duration: Duration(seconds: 5),
));
});
},
),
),
),
);
}),
)
]),
));
}
}
Can someone help? Thanks
Try my code below:
DateTime valueDate = DateTime.now();
Row(
children: <Widget>[
Container(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 0),
child: Text("${valueDate.toLocal()}".split(' ')[0]),
),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: Theme.of(context).accentColor,
width: 2.5,
),
)),
width: 270,
),
RaisedButton(
child: Icon(Icons.date_range),
onPressed: () => _selectDate(context),
)
],
);
The function :
Future<Null> _selectDate(BuildContext context) async {
final DateTime picked = await showDatePicker(context: context, initialDate: valueDate, firstDate: DateTime(2015, 8), lastDate: DateTime(2101));
if (picked != null && picked != valueDate)
setState(() {
valueDate = picked;
});
}
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.