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;
});
}
},
),
]
Related
I tried to calculate age from datepicker but into that datepicker I added sharedpreference.And to calculate age I got "dropdownValueBirthday" equal to " birthday" .Then display null . How I fix this error?
But birthday display nicely
I want calculate age from birthday and should display age as duration.
image
duration is still null
code
void initState() {
super.initState();
dropdownValueBirthday = birthday.first;
checkValueBirthday();
}
//age
String age = "";
DateDuration? duration;
//date picker
//date picker
DateTime? selectedDate;
DateTime now = new DateTime.now();
void showDatePicker() {
DateTime mindate = DateTime(now.year - 2, now.month, now.day - 29);
DateTime maxdate = DateTime(now.year - 1, now.month, now.day);
showCupertinoModalPopup(
context: context,
builder: (BuildContext builder) {
return Container(
height: MediaQuery.of(context).copyWith().size.height * 0.25,
color: Colors.white,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.date,
initialDateTime: mindate,
onDateTimeChanged: (valueBirth) {
if (valueBirth != selectedDate) {
setState(() {
selectedDate = valueBirth;
dropdownValueBirthday =
'${selectedDate?.year}/${selectedDate?.month}/${selectedDate?.day} ';
calAge();
});
}
},
maximumDate: maxdate,
minimumDate: mindate,
),
);
});
}
void calAge() {
DateTime birthday = DateTime.parse(dropdownValueBirthday!);
setState(() {
duration = AgeCalculator.age(birthday);
});
// print('Your age is $duration');
}
String? dropdownValueBirthday;
List<String> birthday = [
'Birthday',
];
checkValueBirthday() {
_getDataBirthday();
}
_saveDataBirthday(String dropdownValueBirthdayShared) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
sharedPreferences.setString("dataBirthday", dropdownValueBirthdayShared);
}
_getDataBirthday() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
dropdownValueBirthday =
sharedPreferences.getString("dataBirthday") ?? birthday.first;
setState(() {});
}
widget code
child: GestureDetector(
onTap: (showDatePicker),
child: SizedBox(
width: 110.0,
height: 25.0,
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white,
),
child: Center(
child: Text(
selectedDate == null
? (dropdownValueBirthday ??
birthday.first)
: '${selectedDate?.year}/${selectedDate?.month}/${selectedDate?.day} ',
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500),
),
),
),
),
),
print
new error
you need to convert string to DateTime
DateTime? birthday = DateTime.parse(dropdownValueBirthday);
To convert a String into a DateTime, you cannot use as. as can be used if the actual type of the object is a child type of it. You can check the type with is. For instance:
void main() {
ParentClass actualParent = ParentClass();
ParentClass hiddenChild = ChildClass();
ChildClass actualChild = ChildClass();
print(actualParent is ChildClass); // false
print(hiddenChild is ChildClass); // true
print(actualChild is ChildClass); // true
}
class ParentClass {
String getType() => 'parent';
}
class ChildClass extends ParentClass {
#override
String getType() => 'child';
}
If you want to convert a String into a DateTime, you have to use DateTime.tryParse(String). See the official docs for more information on DateTime.
EDIT
To calculate the age by a birthday, you need the duration between that day and today (or any other day).
void main() {
DateTime birthday = DateTime.parse("1970-01-01");
DateTime today = DateTime.now();
Duration age = today.difference(birthday);
print('${age.inDays} days'); // 19297 days (at 2022-11-01)
}
Try the following code:
void initState() {
super.initState();
dropdownValueBirthday = birthday.first;
checkValueBirthday();
}
//show date picker
//age
//Radio button variable declare
String age = "";
DateDuration? duration;
//date picker
//date picker
DateTime? selectedDate;
DateTime now = new DateTime.now();
void showDatePicker() {
DateTime mindate = DateTime(now.year - 2, now.month, now.day - 29);
DateTime maxdate = DateTime(now.year - 1, now.month, now.day);
showCupertinoModalPopup(
context: context,
builder: (BuildContext builder) {
return Container(
height: MediaQuery.of(context).copyWith().size.height * 0.25,
color: Colors.white,
child: CupertinoDatePicker(
mode: CupertinoDatePickerMode.date,
initialDateTime: mindate,
onDateTimeChanged: (valueBirth) {
if (valueBirth != selectedDate) {
setState(() {
selectedDate = valueBirth;
dropdownValueBirthday =
'${selectedDate?.year}/${selectedDate?.month}/${selectedDate?.day} ';
});
}
},
maximumDate: maxdate,
minimumDate: mindate,
),
);
});
}
void calAge() {
DateTime birthday = DateTime.parse(dropdownValueBirthday);
setState(() {
duration = AgeCalculator.age(birthday);
});
// print('Your age is $duration');
}
String? dropdownValueBirthday;
List<String> birthday = [
'Birthday',
];
checkValueBirthday() {
_getDataBirthday();
}
_saveDataBirthday(String dropdownValueBirthdayShared) async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
sharedPreferences.setString("dataBirthday", dropdownValueBirthdayShared);
}
_getDataBirthday() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
dropdownValueBirthday =
sharedPreferences.getString("dataBirthday") ?? birthday.first;
setState(() {});
}
I am calculating pregnancy weeks .but the set state only update on second click.
ElevatedButton (
onPressed: () {
setState(() {
_selectDate(context);
sDate = selectedDate;
dueDate = sDate.add(Duration(days: DAYS_IN_PREGNANCY));
DateTime today = DateTime.now();
remaining = today.difference(dueDate).inDays.abs();
daysIn = DAYS_IN_PREGNANCY - remaining;
weekPart = daysIn % 7;
weekValue = daysIn / 7;
week = weekValue + "." + weekPart;
});
},
child: const Text("Choose Date"),
),
_selectDate(BuildContext context) async {
final DateTime? selected = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(2010),
lastDate: DateTime(2025),
);
setState(() {});
selectedDate = selected!;
}
As you can see, your _selectDate function is async and you need to await for it and also you don't need to call setState inside _selectDate, so change you click to this:
ElevatedButton (
onPressed: () async{ //<--- add this
var result = await _selectDate(context); //<--- add this
if(result != null){ //<--- add this
setState(() {
sDate = result; //<--- add this
dueDate = sDate.add(Duration(days: DAYS_IN_PREGNANCY));
DateTime today = DateTime.now();
remaining = today.difference(dueDate).inDays.abs();
daysIn = DAYS_IN_PREGNANCY - remaining;
weekPart = daysIn % 7;
weekValue = daysIn / 7;
week = weekValue + "." + weekPart;
});
}
},
child: const Text("Choose Date"),
),
and change your _selectDate to this:
DateTime? _selectDate(BuildContext context) async {
final DateTime? selected = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(2010),
lastDate: DateTime(2025),
);
return selected;
}
I have this provider class:
import 'package:flutter/material.dart';
class DateProvider with ChangeNotifier {
DateTime? _date1 = null;
DateTime? _date2 = null;
DateTime? get date1 => _date1;
DateTime? get date2 => _date2;
void changeDate1(DateTime? date1) {
_date1 = date1;
notifyListeners();
}
void changeDate2(DateTime? date2) {
_date2 = date2;
notifyListeners();
}
}
I have two TextFormFields wrapped with Selector when I press on the first one to pick date
class _TestState extends State<Test> {
var _formKey = GlobalKey<FormState>();
var _date2Key = GlobalKey<FormState>();
TextEditingController _date1Controller = TextEditingController();
TextEditingController _date2Controller = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Form(
key: _formKey,
child: Column(
children: [
Selector<DateProvider, DateTime?>(
selector: (_, provider) => provider.date1,
builder: (context, date1, child) {
return TextFormField(
controller: _date1Controller,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (value) {
print("Validator $date1");
return;
},
readOnly: true,
onTap: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: date1 != null ? date1 : DateTime.now(),
firstDate: DateTime.now(),
lastDate: DateTime(2101),
);
if (pickedDate != null) {
Provider.of<DateProvider>(context, listen: false)
.changeDate1(pickedDate);
print("TextFormField1 date: $date1");
_date2Key.currentState!.validate();
_formKey.currentState!.validate();
}
},
);
}),
Selector<DateProvider, Tuple2<DateTime?, DateTime?>>(
selector: (_, provider) =>
Tuple2(provider.date1, provider.date2),
builder: (context, data, child) {
return Form(
key: _date2Key,
child: TextFormField(
controller: _date2Controller,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (value) {
print("Validator2 date1 :${data.item1}");
print("Validator2 date2 :${data.item2}");
return;
},
readOnly:
true, //set it true, so that user will not able to edit text
onTap: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate:
data.item2 != null ? data.item2! : DateTime.now(),
firstDate: DateTime.now(),
lastDate: DateTime(2101),
);
if (pickedDate != null) {
Provider.of<DateProvider>(context, listen: false)
.changeDate2(pickedDate);
}
},
),
);
}),
],
),
),
);
}
}
I want to change the date1 in provider class and validate that two textfromfield.
When I pickDate in the first one all the date printed is null knowing that I wrapped the two textformfield with selector
The console shows:
TextFormField1 date: null
Validator2 date1 :null
Validator2 date2 :null
Validator null
why are the values null
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.