IconButton(
onPressed: () async {
DateTime? x = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime.now(),
lastDate: DateTime(2040));
if (x == null) return;
setState(() {
final DateFormat formatter = DateFormat('yyyy-MM-dd');
String formattedDate = formatter.format(x);
print(formattedDate);
print(formattedDate.runtimeType);
});
},
icon: const Icon(UniconsLine.clock)),
Text(formattedDate ?? "EMPTY"),
I am seeing always empty my formattedDate variable below on the build method why doesnt work this code
Could you try to lift up the formattedDate? I think the Problem is that your variable is out of scope.
class DatePicker extends StatefulWidget {
const DatePicker({Key? key}) : super(key: key);
#override
State<DatePicker> createState() => _DatePickerState();
}
class _DatePickerState extends State<DatePicker> {
String? formattedDate;
#override
Widget build(BuildContext context) {
return Column(children: [
IconButton(
onPressed: () async {
DateTime? x = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime.now(),
lastDate: DateTime(2040));
if (x == null) return;
setState(() {
final DateFormat formatter = DateFormat('yyyy-MM-dd');
formattedDate = formatter.format(x);
print(formattedDate);
print(formattedDate.runtimeType);
});
},
icon: const Icon(Icons.date_range)),
Text(formattedDate ?? "EMPTY"),
]);
}
}
The problem is in the scope of your variable formattedDate. It only exists inside setState because it was declared there.
Declare it at the beginning of the class.
You have redefined formattedDate inside setState() as a local variable. The field formattedDate you are using in Text(formattedDate ?? "EMPTY") is a totally different variable. It remains null, as you are not changing it at all. Just remove the String before formattedDate and it should be fine.
final DateFormat formatter = DateFormat('yyyy-MM-dd');
formattedDate = formatter.format(x); <-- This is your problem
print(formattedDate);
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;
});
}
},
),
]
This is the screenshot of dialog box where i want to update new date after picked up.
This is what i tried in controller.dart.
class AppointmentController extends GetxController {
String t;
var selectedDate = DateTime.now().obs;
var selectedTime = TimeOfDay.now().obs;
void selectDate() async {
final DateTime pickedDate = await showDatePicker(
context: Get.context,
initialDate: selectedDate.value,
firstDate: DateTime(2018),
lastDate: DateTime(2025),
);
if (pickedDate != null && pickedDate != selectedDate.value) {
selectedDate.value = pickedDate;
}
}
This is what I tried in homepage.dart
Obx(
()=>TextFormField(
onTap:(){
controller.selectDate();
},
initialValue:DateFormat('DD-MM-
yyyy').format(controller.selectedDate.value).toString(),
),
add a TextEditingController to the textformfield and change text with this controller
class AppointmentController extends GetxController {
String t;
var selectedDate = DateTime.now().obs;
var selectedTime = TimeOfDay.now().obs;
TextEditingController textEditingController=TextEditingController();
void selectDate() async {
final DateTime pickedDate = await showDatePicker(
context: Get.context,
initialDate: selectedDate.value,
firstDate: DateTime(2018),
lastDate: DateTime(2025),
);
if (pickedDate != null && pickedDate != selectedDate.value) {
selectedDate.value = pickedDate;
textEditingController.text=DateFormat('DD-MM-
yyyy').format(selectedDate.value).toString();
}
}
Obx(
()=>TextFormField(
controller:controller.textEditingController,
onTap:(){
controller.selectDate();
},
initialValue:DateFormat('DD-MM-
yyyy').format(DateTime.now()).toString(),
),
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.
I have an array with certain dates.
I want to disable these dates in the date picker and also change the color. How to do this?
You can use selectableDayPredicate property. For colors, you can change it by themes.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
DateTime selectedDate = DateTime(2020, 1, 14);
// DatePicker will call this function on every day and expect
// a bool output. If it's true, it will draw that day as "enabled"
// and that day will be selectable and vice versa.
bool _predicate(DateTime day) {
if ((day.isAfter(DateTime(2020, 1, 5)) &&
day.isBefore(DateTime(2020, 1, 9)))) {
return true;
}
if ((day.isAfter(DateTime(2020, 1, 10)) &&
day.isBefore(DateTime(2020, 1, 15)))) {
return true;
}
if ((day.isAfter(DateTime(2020, 2, 5)) &&
day.isBefore(DateTime(2020, 2, 17)))) {
return true;
}
return false;
}
Future<void> _selectDate(BuildContext context) async {
final DateTime picked = await showDatePicker(
context: context,
initialDate: selectedDate,
selectableDayPredicate: _predicate,
firstDate: DateTime(2019),
lastDate: DateTime(2021),
builder: (context, child) {
return Theme(
data: ThemeData(
primaryColor: Colors.orangeAccent,
disabledColor: Colors.brown,
textTheme:
TextTheme(body1: TextStyle(color: Colors.blueAccent)),
accentColor: Colors.yellow),
child: child,
);
});
if (picked != null && picked != selectedDate)
setState(() {
selectedDate = picked;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text("${selectedDate.toLocal()}".split(' ')[0]),
SizedBox(
height: 20.0,
),
RaisedButton(
onPressed: () => _selectDate(context),
child: Text('Select date'),
),
],
),
),
);
}
}
I encountered the same problem. After going back and forth, I did the following:
Created a list of specific dates:
static var unavailableDates = ["2020-08-14", "2020-08-20", "2020-08-13","2020-08-21","2020-08-23"];
Created an initial date variable:
static DateTime initialDate = DateTime.now();
formatted the initial date to get rid of the timestamp:
static DateFormat dateFormat = new DateFormat("yyyy-MM-dd");
String formattedDate = dateFormat.format(initialDate);
Put my unavailable dates in order:
unavailableDates.sort(((a, b) => a.compareTo(b)));
Added a way to verify the initial date does not fall on the disabled date. This jumps to the next available date. If you do not have something in place to verify unavailable date and initial date is not the same, you will get an exception:
for(var unavdate in unavailableDates){
if (unavdate.compareTo(formattedDate) == 0) {
formattedDate = unavdate;
fromStringDate = DateTime.parse(formattedDate);
initialDate = fromStringDate.add(new Duration(days: 1));
formattedDate = dateFormat.format(initialDate);
}
}
Created a day predicate function:
bool setDayPredicate(DateTime val) {
//this allows certain dates to be greyed out based on availability
String Dates = dateFormat.format(val); //formatting passed in value
return !unavailableDates.contains(Dates);
}
Put it all together:
date = await showDatePicker(
context: context,
initialDate: initialDate,
firstDate: new DateTime.now(),
lastDate: new DateTime.now().add(new Duration(days: 30)),
selectableDayPredicate: setDayPredicate, });