Flutter how to display datepicker when textformfield is clicked - flutter

new TextFormField(
decoration: new InputDecoration(hintText: 'DOB'),
maxLength: 10,
validator: validateDob,
onSaved: (String val) {
strDob = val;
},
),
Future _selectDate() async {
DateTime picked = await showDatePicker(
context: context,
initialDate: new DateTime.now(),
firstDate: new DateTime(2016),
lastDate: new DateTime(2019)
);
if(picked != null) setState(() => _value = picked.toString());
}
I created one textFormField when i click the field i want to display datepicker then i have to select one date from the picker after selecting the date i want to set the selected date in the textFormField.

Update 2020:
As pointed by another answer #Lekr0 this can now be done using onTap() property of TextFormField.
TextFormField(
onTap: (){
// Below line stops keyboard from appearing
FocusScope.of(context).requestFocus(new FocusNode());
// Show Date Picker Here
},
)
Original Answer:
Simple Way of Doing it :
Wrap your TextFormField with IgnorePointer & wrap IgnorePointer with InkWell
InkWell(
onTap: () {
_selectDate(); // Call Function that has showDatePicker()
},
child: IgnorePointer(
child: new TextFormField(
decoration: new InputDecoration(hintText: 'DOB'),
maxLength: 10,
// validator: validateDob,
onSaved: (String val) {},
),
),
),
Also in Your _selectDate() make lastDate: new DateTime(2020)); else you will get error.

TextEditingController dateCtl = TextEditingController();
TextFormField(
controller: dateCtl,
decoration: InputDecoration(
labelText: "Date of birth",
hintText: "Ex. Insert your dob",),
onTap: () async{
DateTime date = DateTime(1900);
FocusScope.of(context).requestFocus(new FocusNode());
date = await showDatePicker(
context: context,
initialDate:DateTime.now(),
firstDate:DateTime(1900),
lastDate: DateTime(2100));
dateCtl.text = date.toIso8601String();},)

You can use OnTap property to achieve this
TextFormField(
onTap: (){
// Below line stops keyboard from appearing
FocusScope.of(context).requestFocus(new FocusNode());
// Show Date Picker Here
},
)

To stop keyboard from appearing, you can set the readOnly property of the TextFormField to true.
TextFormField(
readOnly: true,
...
);

TextEditingController intialdateval = TextEditingController();
Future _selectDate() async {
DateTime picked = await showDatePicker(
context: context,
initialDate: new DateTime.now(),
firstDate: new DateTime(2020),
lastDate: new DateTime(2030));
if (picked != null)
setState(
() => { data.registrationdate = picked.toString(),
intialdateval.text = picked.toString()
}
);
}
TextFormField(
// focusNode: _focusNode,
keyboardType: TextInputType.phone,
autocorrect: false,
controller: intialdateval,
onSaved: (value) {
data.registrationdate = value;
},
onTap: () {
_selectDate();
FocusScope.of(context).requestFocus(new FocusNode());
},
maxLines: 1,
//initialValue: 'Aseem Wangoo',
validator: (value) {
if (value.isEmpty || value.length < 1) {
return 'Choose Date';
}
},
decoration: InputDecoration(
labelText: 'Registration Date.',
//filled: true,
icon: const Icon(Icons.calendar_today),
labelStyle:
TextStyle(decorationStyle: TextDecorationStyle.solid),
),
),

I don't know why you want to display DatePicker on click of TextFormField?
BTW you have to set enabled=false property of TextFormField and warp TextFormField to GestureDetector that has onTap property where you can call your DatePicker Method.

final _dateController = useTextEditingController();
TextFormField(
readOnly: true,
controller: _dateController,
decoration: InputDecoration(
labelText: 'Date',
),
onTap: () async {
await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2015),
lastDate: DateTime(2025),
).then((selectedDate) {
if (selectedDate != null) {
_dateController.text =
DateFormat('yyyy-MM-dd').format(selectedDate);
}
});
},
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter date.';
}
return null;
},
)

Try this!
GestureDetector(
onTap: () {
var tm = showCupertinoDatePicker(
firstDate:
defaultDateTime.add(Duration(days: -1)),
lastDate: defaultDateTime.add(Duration(days: 1)),
context: context,
initialDate: newDate);
tm.then((selectedDate) {
if (selectedDate != null) {
setState(() {
newDate = selectedDate;
});
dateController.text =
"${DateTimeUtils.formatDate(newDate)}";
}
});
},
child: AbsorbPointer(
child: TextFormField(
controller: dateController,
autofocus: false,
validator: ((val) {
if (val.trim().isEmpty) {
return “Select Date";
}
return null;
}),
decoration: InputDecoration(
icon: Icon(Icons.today),
suffix: Text("Tap to change",
style: Theme.of(context)
.textTheme
.caption))),
),
),
I'm using all place comman widget

Related

How do I set the style of the text in DateFormat in Flutter?

InkWell(
child: TextFormField(
readOnly: true,
textAlign: TextAlign.center,
onTap: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(1900),
lastDate: DateTime.now());
if (pickedDate != null) {
setState(() {
_date.text = DateFormat('dd-MM-yyyy').format(pickedDate);
});
}
},
controller: _date,
hintStyle: bmiTextForm,
hintText: 'Doğum Gününüz'),
),
),
HintStyle on the first image changes after selecting a date. How can I set the hintStyle of the DateFormat?
Use the same textStyle on TextFormField's style as you did for hintText.
controller: _date,
style: bmiTextForm,
decoration: InputDecoration(
hintStyle: bmiTextForm,
hintText: 'Doğum Gününüz',
),

Flutter Date Picker function for multiple fields

How to use the below code for single function multiple textformfield controller to pass the date value. Or I have to write multiple function for all controllers in the form fields for date picker ?
....
TextFormField(
decoration: inputDecoration(
'Enter Start Date',
'Start Date',
datestartCtrl),
controller: datestartCtrl,
onTap: () => _selectDate(context),
),
SizedBox(
height: 10,
),
TextFormField(
decoration: inputDecoration(
'Enter Finish Date',
'Date Finished',
datefinishCtrl),
controller: datefinishCtrl,
onTap: () => _selectDate(context),
),
.....
Future<Null> _selectDate(BuildContext context) async {
var selectedDate = DateTime.now();
DateFormat formatter = DateFormat('dd MMMM yyyy');//specifies day/month/year format
final DateTime? picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1901, 1),
lastDate: DateTime.now());
if (picked != null && picked != selectedDate)
setState(() {
selectedDate = picked;
datestartCtrl.value = TextEditingValue(text: formatter.format(picked));//Use formatter to format selected date and assign to text field
});
}
TextFormField(
decoration: inputDecoration(
'Enter Start Date',
'Start Date',
datestartCtrl),
controller: datestartCtrl,
onTap: () => _selectDate(context,datestartCtrl),
),
SizedBox(
height: 10,
),
TextFormField(
decoration: inputDecoration(
'Enter Finish Date',
'Date Finished',
datefinishCtrl),
controller: datefinishCtrl,
onTap: () => _selectDate(context,datefinishCtrl),
),
Method for datepicker
Future<Null> _selectDate(BuildContext context, TextEditingController controller) async {
var selectedDate = DateTime.now();
DateFormat formatter = DateFormat('dd MMMM yyyy');
final DateTime? picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1901, 1),
lastDate: DateTime.now());
if (picked != null && picked != selectedDate)
setState(() {
controller.value = TextEditingValue(text: formatter.format(picked));
});
}
Textfield code :
TextFormField(
decoration: inputDecoration(
'Enter Start Date',
'Start Date',
datestartCtrl),
controller: datestartCtrl,
onTap: () => _selectDate(context,datestartCtrl),
),
SizedBox(
height: 10,
),
TextFormField(
decoration: inputDecoration(
'Enter Finish Date',
'Date Finished',
datefinishCtrl),
controller: datefinishCtrl,
onTap: () => _selectDate(context,datefinishCtrl),
),
Method For Datepicker
Future<Null> _selectDate(BuildContext context, TextEditingController controller) async {
var selectedDate = DateTime.now();
DateFormat formatter = DateFormat('dd MMMM yyyy');
final DateTime? picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1901, 1),
lastDate: DateTime.now());
if (picked != null && picked != selectedDate)
setState(() {
selectedDate = picked;
controller.text = picked.tostring();
});
}
Hope you got the solution!

Flutter - calling setState() before the build

I use a futureBuilder to display date inside TextFormFields, if there is data in the webservice I call in the futureBuilder for the date I selected in the DateTimePicker, the TextFormField is disabled and the data is displayed in it. Else, the textFormField is enabled.
I also have a button that I want to disable if there is data received and enable if there isn't, so I used a boolean.
Here is my code :
child: FutureBuilder<double?>(
future: getTimes(selectedDate),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData){
_timeController.clear();
setState(() {
_isButtonDisabled = false;
});
return TextFormField(
controller: _timeController,
textAlign: TextAlign.center,
enabled: false,
decoration: InputDecoration(
hintText: snapshot.data.toString() + " h",
contentPadding: EdgeInsets.zero,
filled: true,
fillColor: Colors.white70
),
);
}
else {
setState(() {
_isButtonDisabled = true;
});
return TextFormField(
controller: _timeController,
textAlign: TextAlign.center,
enabled: true,
decoration: InputDecoration(
hintText: "0 h",
contentPadding: EdgeInsets.zero,
filled: true,
fillColor: Colors.white
),
);
}
}
)
This was causing me the error setState() or markNeedsBuild called during build , so thanks to the answers of this topic I encapsulated the setState method in WidgetsBinding.instance.addPostFrameCallback((_)
Here is what my code looks like now :
child: FutureBuilder<double?>(
future: getTimes(selectedDate),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData){
_timeController.clear();
WidgetsBinding.instance?.addPostFrameCallback((_){
setState(() {
_isButtonDisabled = false;
});
});
return TextFormField(
controller: _timeController,
textAlign: TextAlign.center,
enabled: false,
decoration: InputDecoration(
hintText: snapshot.data.toString() + " h",
contentPadding: EdgeInsets.zero,
filled: true,
fillColor: Colors.white70
),
);
}
else {
WidgetsBinding.instance?.addPostFrameCallback((_){
setState(() {
_isButtonDisabled = true;
});
});
return TextFormField(
controller: _timeController,
textAlign: TextAlign.center,
enabled: true,
decoration: InputDecoration(
hintText: "0 h",
contentPadding: EdgeInsets.zero,
filled: true,
fillColor: Colors.white
),
);
}
}
)
The problem that I have now is my TextFormFields aren't clickable anymore, and the button is always enabled, may be a misused / misunderstood the addPostFrameCallback function.
Thanks for helping,
You have DateTimePicker, after the selecting date-time you can call the future.
getTimes() returns nullable double. Before retuning data, compare value is null or not and set _isButtonDisabled based on it, assign true/false.
bool _isButtonDisabled = true; // set the intial/watting state you want
Future<double?> getTimes(DateTime time) async {
//heavy operations
return await Future.delayed(Duration(seconds: 3), () {
return 4; //check with null +value
});
}
----
#override
Widget build(BuildContext context) {
print("rebuild");
return Column(
children: [
ElevatedButton(
onPressed: () async {
final selectedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime.now().subtract(Duration(days: 4444)),
lastDate: DateTime.now().add(Duration(days: 4444)),
);
if (selectedDate == null) return;
final response = await getTimes(selectedDate);
print(response);
setState(() {
_isButtonDisabled = response != null;
});
},
child: Text("Select Date"),
),
ElevatedButton(
onPressed: _isButtonDisabled ? null : () {}, child: Text("t"))
],
);}

ShowTimePicker i need to show the time picker on text field

defultFormField(
controller: timeController,
onSubmit: () {},
onTap: () {
showTimePicker(
useRootNavigator: true,
context: context,
initialTime: TimeOfDay.now(),
).then((value) {
print(value);
});
},
and this is the components
Widget defultFormField({
required Function onTap,
required Function onSubmit,
required TextEditingController controller,
// required TextInputType type,
required String text,
required IconData prefix,
required Function valedate,
}) =>
TextFormField(
controller: controller,
// keyboardType: type,
onTap: () {},
onFieldSubmitted: (s) {},
validator: (s) {
valedate();
},
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: text,
prefixIcon: Icon(prefix),
),
);
Try below code hope its helpful to you. Or you can used this package also.
Declare TimeOfDay class
TimeOfDay _time = TimeOfDay(hour: 00, minute: 00);
Create function for TimePicker
void _selectTime() async {
final TimeOfDay? newTime = await showTimePicker(
context: context,
initialTime: _time,
);
if (newTime != null) {
setState(() {
_time = newTime;
});
}
}
Your Widget
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
decoration: InputDecoration(
hintText: 'Select Time',
border: OutlineInputBorder(),
),
onTap: _selectTime,
),
),
SizedBox(height: 8),
Text(
'Selected time: ${_time.format(context)}',
),
],
),

How to show date picker on the onclick of text field instead of keyboard in flutter?

Wish to show date picker when clicking on the TextFormField instead of the keyboard. I have tried using GestureDetector but not working as I expected.
DateTime _date = new DateTime.now();
TimeOfDay _time = new TimeOfDay.now();
Future<Null> _selectedDate(BuildContext context) async {
final DateTime picked = await showDatePicker(
context: context,
initialDate: _date,
firstDate: new DateTime(2016),
lastDate: new DateTime(2019));
if (picked != null && picked != _date) {
print("Date selected ${_date.toString()}");
setState(() {
_date = picked;
});
}
}
......
new GestureDetector(
onTap: (){
_selectedTime(context);
},
child:
new TextFormField(
initialValue: convertToDate(_date),
decoration: const InputDecoration(
icon: const Icon(Icons.calendar_today),
hintText: 'Enter your date of event',
labelText: 'Date',
),
keyboardType: null,
),
),
You can wrap your TextField with AbsorbPointer , so your widget tree would look something like this:
GestureDetector(
onTap:()=>showDialog(),
child:AbsorbPointer(
child: MyTextField(),
)
)
You can wrap your TextFormField with an AbsorbPointer (see documentation). It will "absorb" the incoming standard behavior on the child so clicking the TextFormField would do nothing. If you now wrap the AbsorbPointerusing a GestureDetector you can use the onTap() method to call your showDatePicker method.
DateTime selectedDate = DateTime.now();
TextEditingController _date = new TextEditingController();
Future<Null> _selectDate(BuildContext context) async {
final DateTime picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1901, 1),
lastDate: DateTime(2100));
if (picked != null && picked != selectedDate)
setState(() {
selectedDate = picked;
_date.value = TextEditingValue(text: picked.toString());
});
}
// inside Widget build
GestureDetector(
onTap: () => _selectDate(context),
child: AbsorbPointer(
child: TextFormField(
controller: _date,
keyboardType: TextInputType.datetime,
decoration: InputDecoration(
hintText: 'Date of Birth',
prefixIcon: Icon(
Icons.dialpad,
color: _icon,
),
),
),
),
);
The other answers here have many widgets to get the job done. But this can simply done by using TextFormField only. Just set the widget to read only (so that it doesn't take inputs) and then define an onTap. The controller attached to it will take the value from the date picker.
First create a TextFormField widget like this:
TextFormField(
readOnly: true, //this is important
onTap: _selectDate, //the method for opening data picker
controller: _textcontroller, //the controller
),
Now write the _selectDate function:
DateTime dateTime = DateTime.now();
_selectDate() async {
final DateTime? picked = await showDatePicker(
context: context,
initialDate: dateTime,
initialDatePickerMode: DatePickerMode.day,
firstDate: DateTime.now(),
lastDate: DateTime(2101));
if (picked != null) {
dateTime = picked;
//assign the chosen date to the controller
_textController.text = DateFormat.yMd().format(dateTime);
}
}
Personally I think this is the easiest solution.
Try this
GestureDetector(
onTap: () => _selectDate(context),
child: AbsorbPointer(
child: TextField(
controller: textController,
decoration: InputDecoration(
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
contentPadding: EdgeInsets.all(10.0),
labelText: widget.hintText,
labelStyle: TextStyle(
color: Colors.black,
fontSize: 16),
// pass the hint text parameter here
hintStyle: TextStyle(
color: Colors.black,
fontSize: 16),
suffixIcon: Icon(
Icons.calendar_today),
),
style: TextStyle(color: Colors.black, fontSize: 18),
),
),
);
Future<Null> _selectDate(BuildContext context) async {
final DateTime? picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1901, 1),
lastDate: DateTime(2100));
if (picked != null && picked != selectedDate)
setState(() {
selectedDate = picked;
String convertedDateTime = "${picked.year.toString()}-${picked.month.toString().padLeft(2,'0')}-${picked.day.toString().padLeft(2,'0')}";
// widget.textController.value = TextEditingValue(text: picked.toString());
widget.textController.value = TextEditingValue(text: convertedDateTime);;
});
}
Result
TextField(
controller: TextEditingController()
..text = reservationProvider.date,
decoration: InputDecoration(
suffixIcon: ImageIcon(
AssetImage('images/calendar_today.png'),
color: Colors.black,
)),
readOnly: true,
onTap: () async {
final date = await showDatePicker(
context: context,
firstDate: DateTime(1960),
initialDate: DateTime.now(),
lastDate: DateTime(2100));
if (date != null) {
print(date);
}
},
),