I am basically trying to create a signup screen for my app. I have already included all of the other TextFormField for the other data. However, I am now stuck on the date input section, I managed to create a TextFormField wrapped in a GestureDetector where it will open a date picker to select a date once the TextFormField is tapped. My problem is I want to set the value of the the date TextFormField with the date selected in the date picker, I don't know why with the code that I have it is very inconsistent, at times it does display the date and other times it doesn't update and keeps showing the hintText, and also since there is a date picker popping up when the field is tapped, how could I disable the keyboard from showing when focusing on the date field.
class DateState extends StatefulWidget {
const DateState({
Key key,
}) : super(key: key);
#override
_DateState createState() => _DateState();
}
class _DateState extends State<DateState> {
DateTime selectedDate = DateTime.now();
Future<Null> _selectDate(BuildContext context) async {
final DateTime picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1950),
lastDate: DateTime.now());
if (picked != null && picked != selectedDate)
setState(() {
selectedDate = picked;
});
}
#override
Widget build(BuildContext context) {
var dateValue = TextEditingController();
return DateFieldContainer(
child: GestureDetector(
child: TextFormField(
controller: dateValue,
onTap: () {
_selectDate(context);
dateValue.text = "${selectedDate.toLocal()}".split(' ')[0];
},
decoration: InputDecoration(
hintText: "Select Date",
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: PrimaryColor),
),
),
),
),
);
}
}
Just replace your _selectDate() with below code.
void _selectDate(){
showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1950),
lastDate: DateTime.now(),
).then((pickedDate) {
if (pickedDate == null) {
return;
}
setState(() {
selectedDate = pickedDate;
dateValue.text = "${selectedDate.toLocal()}".split(' ')[0];
});
});
}
Replace your onTap() implementation with below code
onTap: () {
_selectDate();
}
Keep var dateValue = TextEditingController(); outside build() method.
Related
How do I change the format of the date? I am using a datepicker to pick a date but I want the date to display as dd/mm/yyyy, here is the code
class DatePicker extends StatefulWidget {
const DatePicker({Key? key}) : super(key: key);
#override
State<DatePicker> createState() => _DatePickerState();
}
class _DatePickerState extends State<DatePicker> {
DateTime selectedDate = DateTime.now();
Future<void> _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;
});
}
}
#override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
InkWell(
onTap: () => _selectDate(context),
child: Text("${selectedDate.toLocal()}".split(' ')[0])),
SizedBox(
height: 20.0,
),
],
);
}
}
Try using instead of
child: Text("${selectedDate.toLocal()}".split(' ')[0])),
do
child: Text(DateFormat('dd/MM/yyyy').format(selectedDate)),
Please try this
var formattedSelectedDate;
if (picked != null && picked != selectedDate) {
setState(() {
final DateFormat formatter = DateFormat('yyyy-MM-dd');
final String formatted = formatter.format(picked);
print(formatted);
selectedDate = picked;
formattedSelectedDate = formatted;
});
}
Use this "formattedSelectedDate" to display on the UI.
For displaying the date you should use this
Text("${selectedDate.day}/${selectedDate.month}/${selectedDate.year}"),
I have two TextFormField startdate and enddate that takes date as a input from date picker. i want to restrict that user can not allow to select enddate before selected startdate.Be able to select from after selected startdate.how can i manage that.
Here is my cample code
TextFormField(
controller: startDate,
readOnly: true,
validator: (startDate){
if(startDate==null|| startDate.isEmpty){
return "Please Input Start Date";
}else return null;
},
onTap: () async{
DateTime? startPickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate:DateTime.now(),
lastDate: DateTime(2100)
);
if(startPickedDate!= null){
String formattedDate = DateFormat('dd-MM-yyyy').format(startPickedDate);
setState(() {
startDate.text = formattedDate; //set output date to TextField value.
});
}
},
)
TextFormField(
controller: endDate,
readOnly: true,
validator: (endDate){
if(endDate==null || endDate.isEmpty){
return "Please Input End Date";
}else return null;
},
onTap: () async{
DateTime? endPickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime.now(),
lastDate: DateTime(2100),
);
if(endPickedDate!= null){
String formattedDate = DateFormat('dd-MM-yyyy').format(endPickedDate);
setState(() {
endDate.text = formattedDate;
}
);
}
},
),
All you need is a check to see if startDate controller is empty or not. If it is not empty show date picker. Check the following code for implementation:
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
late TextEditingController startDate;
late TextEditingController endDate;
#override
void initState() {
startDate = TextEditingController();
endDate = TextEditingController();
super.initState();
}
#override
Widget build(BuildContext context) {
return Column(
children: [
TextFormField(
controller: startDate,
readOnly: true,
validator: (startDate){
if(startDate==null|| startDate.isEmpty){
return "Please Input Start Date";
}else return null;
},
onTap: () async{
DateTime? startPickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate:DateTime.now(),
lastDate: DateTime(2100)
);
if(startPickedDate!= null){
String formattedDate = DateFormat('dd-MM-yyyy').format(startPickedDate);
setState(() {
startDate.text = formattedDate; //set output date to TextField value.
});
}
},
),
TextFormField(
controller: endDate,
readOnly: true,
validator: (endDate){
if(endDate==null || endDate.isEmpty){
return "Please Input End Date";
}else {
return null;
}
},
onTap: () async{
if (startDate.text.isNotEmpty) {
String dateTime = startDate.text;
DateFormat inputFormat = DateFormat('dd-MM-yyyy');
DateTime input = inputFormat.parse(dateTime);
DateTime? endPickedDate = await showDatePicker(
context: context,
initialDate: input.add(const Duration(days: 1)),
firstDate: input.add(const Duration(days: 1)),
lastDate: DateTime(2100),
);
if(endPickedDate!= null){
String formattedDate = DateFormat('dd-MM-yyyy').format(endPickedDate);
setState(() {
endDate.text = formattedDate;
}
);
}
} else {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('You need to select Start Date')));
}
},
),
],
);
}
}
You can check the text of startDate controller. If it is empty (i.e ''), the date picker will not be triggered.
controller: endDate,
readOnly: true,
validator: (endDate) {
if (endDate == null || endDate.isEmpty) {
return "Please Input End Date";
} else
return null;
},
onTap: () async {
if (startDate.text.isNotEmpty) {
DateTime? endPickedDate = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime.now(),
lastDate: DateTime(2100),
);
if (endPickedDate != null) {
String formattedDate = DateFormat('dd-MM-yyyy').format(endPickedDate);
setState(() {
endDate.text = formattedDate;
});
}
}
},
),
DateTime? startPickedDate
Define this variable outside the build method. When the start date is selected update this variable. Then in end date add this variable as the first date in date picker
Please update your Text form fields with the below code.
Added Text formfield and the start & end date. I have set 40 days range initially for start and end date. you can update this as per your need.
TextEditingController startDateController = TextEditingController();
TextEditingController endDateController = TextEditingController();
DateTime startDate = DateTime.now().subtract(Duration(days: 40));
DateTime endDate = DateTime.now().add(Duration(days: 40));
Build method column code
Column(children: [
TextFormField(
controller: startDateController,
readOnly: true,
validator: (startDate) {
if (startDate == null || startDate.isEmpty) {
return "Please Input Start Date";
} else
return null;
},
onTap: () async {
DateTime? startPickedDate = await showDatePicker(
context: context,
fieldLabelText: "Start Date",
initialDate: startDate,
firstDate: startDate,
lastDate: endDate);
if (startPickedDate != null) {
String formattedDate =
DateFormat('dd-MM-yyyy').format(startPickedDate);
setState(() {
startDate = startPickedDate;
startDateController.text =
formattedDate; //set output date to TextField value.
});
}
},
),
TextFormField(
controller: endDateController,
readOnly: true,
validator: (endDate) {
if (endDate == null || endDate.isEmpty) {
return "Please Input End Date";
} else
return null;
},
onTap: () async {
DateTime? endPickedDate = await showDatePicker(
context: context,
fieldLabelText: "End Date",
initialDate: startDate,
firstDate: startDate,
lastDate: endDate,
);
if (endPickedDate != null) {
String formattedDate =
DateFormat('dd-MM-yyyy').format(endPickedDate);
setState(() {
endDate = endPickedDate;
endDateController.text = formattedDate;
});
}
},
),
]
I have DateTimeField and there is strange issue while editing the date manually.
Here is the display with default value:
I selected month by double tapping and try to type 08 manually.
When I bring pointer at the end of month 12, and pressed backspace to remove 2 from 12. The month was changed to 01.
When I press backspace in the end of year, to remove 8 from 2018. It was changed to 0201.
Here is the code of that field:
DateTimeField(
format: DateFormat("yyyy-MM-dd hh:mm:ss"),
onSaved: (val) => setState(() => _fromDate = val),
keyboardType: TextInputType.datetime,
onChanged: (DateTime newValue) {
setState(() {
_fromDate = newValue;
});
},
onShowPicker: (context, currentValue) {
return showDatePicker(
context: context,
firstDate: DateTime.now(),
initialDate: currentValue ?? DateTime.now(),
lastDate: DateTime.now().add(new Duration(days: 30))
);
},
);
I have no clue, what's going on with this. Please tell me, what could be wrong?
NOTE:
Using picker for date selection works fine
I've date field in another page, it's in yyyy-MM-dd format, and it works as expected there.
So I've tried the available sample that you've provided. I got a different behavior, I'm not able to edit the value manually. The date picker always open whenever I've tried to edit the form.
Here is the complete minimal code that I've tested base from your code:
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:datetime_picker_formfield/datetime_picker_formfield.dart';
void main() => runApp(BasicDateTimeField());
class BasicDateTimeField extends StatefulWidget {
#override
_BasicDateTimeFieldState createState() => _BasicDateTimeFieldState();
}
class _BasicDateTimeFieldState extends State<BasicDateTimeField> {
#override
Widget build(BuildContext context) {
DateTime _fromDate;
return MaterialApp(
home: Scaffold(
body: Center(
child: DateTimeField(
format: DateFormat("yyyy-MM-dd hh:mm:ss"),
onSaved: (val) => setState(() => _fromDate = val),
keyboardType: TextInputType.datetime,
onChanged: (DateTime newValue) {
setState(() {
_fromDate = newValue;
});
},
onShowPicker: (context, currentValue) {
return showDatePicker(
context: context,
firstDate: DateTime.now(),
initialDate: currentValue ?? DateTime.now(),
lastDate: DateTime.now().add(new Duration(days: 30)));
},
),
),
),
);
}
}
Output:
In the sample, I've used the current version of datetime_picker_formfield: ^2.0.0 plugin.
Perhaps you can use the built-in DateTime picker instead.
Here is a sample demo that I've created for your reference:
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
theme: ThemeData(primaryColor: Colors.blue),
home: MyWidget(),
),
);
}
class MyWidget extends StatefulWidget {
createState() => MyWidgetState();
}
class MyWidgetState extends State<MyWidget> {
DateTime selectedDate = DateTime.now();
Future<void> _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;
});
}
#override
initState() {
super.initState();
selectedDate = DateTime.now();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Demo App"),
),
body: ListView(padding: const EdgeInsets.all(16.0), children: [
Container(
height: 100,
child: FlutterLogo(),
),
SizedBox(height: 10.0),
InputDatePickerFormField(
firstDate: DateTime(2015, 8),
lastDate: DateTime(2101),
initialDate: selectedDate,
onDateSubmitted: (date) {
setState(() {
selectedDate = date;
});
},
),
// Text("Selected Date: $selectedDate"),
ElevatedButton(
onPressed: () => _selectDate(context),
child: Text('Select date'),
)
]),
);
}
}
Output:
This behavior means that you can not manually change the date select use your picker to change it
I'm having trouble setting the state to get the value from textfield with a date picker.
How do you return the value in the text field if the date picked is between start and end. I set pressed initially to false and when it's press it becomes true which will return the value from the text field.
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
home: MyApp(),
));
class MyApp extends StatefulWidget {
#override
MyAppState createState() {
return new MyAppState();
}
}
class MyAppState extends State<MyApp> {
bool pressed = false;
final myController = TextEditingController();
DateTime selectedDate = DateTime.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;
});
}
#override
void dispose() {
// Clean up the controller when the widget is disposed.
myController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Route'),
),
body: Column(
children: <Widget>[
TextField(
controller: myController,
decoration: new InputDecoration(labelText: "Enter a number"),
keyboardType: TextInputType.number,
),
SizedBox(
height: 50.0,
),
RaisedButton(
onPressed: () => _selectDate(context),
child: Text('Select date'),
),
RaisedButton(
child: Text("show text"),
onPressed: () {
DateTime start = DateTime(2019, 01, 01);
final end = DateTime(2022, 12, 31);
if (selectedDate.isAfter(start) && selectedDate.isBefore(end)) {
return pressed = true;
} else {
return pressed = false;
}
},
),
pressed ? Text(myController.text) : Text('no'),
],
),
);
}
}
final myController = TextEditingController();
DateTime selectedDate = DateTime.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;
myController.text = selectedDate.toString();
});
}
I have two separate buttons, one to select a date and one to select a time. How am I able to select both the date and then time by only having a single button?
For example, one the click of a "Schedule" button, a Datepicker will popup. Once the user selects a date and clicks "OK" in the Datepicker, the Timepicker will be called or popup.
This is the code for my time and date button widgets:
DateTime _date = new DateTime.now();
TimeOfDay _time = new TimeOfDay.now();
Future<Null> _selectDate(BuildContext context) async {
final DateTime picked = await showDatePicker(
context: context,
initialDate: _date,
firstDate: new DateTime(2019),
lastDate: new DateTime(2021),
);
if(picked != null && picked != _date) {
print('Date selected: ${_date.toString()}');
setState((){
_date = picked;
});
}
}
Future<Null> _selectTime(BuildContext context) async {
final TimeOfDay picked = await showTimePicker(
context: context,
initialTime: _time,
);
if(picked != null && picked != _time) {
print('Time selected: ${_time.toString()}');
setState((){
_time = picked;
});
}
}
Widgets:
final buttonRow = new Wrap(children: <Widget>[
new RaisedButton(
child: new Text('Select Date'),
onPressed: (){_selectDate(context);}
),
new RaisedButton(
child: new Text('Select Time'),
onPressed: (){_selectTime(context);}
)
]);
RaisedButton(
child: new Text('Select Date and Time'),
onPressed: (){ _selectDateAndTime(context); }
)
/* ... */
Future<Null> _selectDateAndTime(BuildContext context) async {
await _selectDate(context);
await _selectTime(context);
}