Search code examples
flutterflutter-dependencies

Bug , Cannot select current date without changing to a different date first in flutter


date picker field

enter image description here

date picker

enter image description here

In the current implementation, the default date displayed is today's date. However, if a user wishes to select the current date, they must first change the date and then reselect today's date. I would like to address this issue by making the birthday field initially display the current date. When the user clicks on the field, the date picker should open and show today's date. If the user doesn't select a different date or wants to select today's date, they should be able to do so by clicking anywhere on the screen (automatically minimizing the date picker) or by clicking the date picker itself, which should select and display today's date.

code

ui code

         GestureDetector(
              onTap: () => showDatePicker(context),
              child: SizedBox(
                width: width * 0.9,
                height: height * 0.06,
                child: Container(
                  decoration: BoxDecoration(
                    color: Colors.white,
                    border: Border.all(
                      color: Colors.black,
                      width: 1.0,
                    ),
                    borderRadius: BorderRadius.circular(15),
                  ),
                  child: Padding(
                    padding: EdgeInsets.only(
                        left: width * 0.060, top: height * 0.018),
                    child: Text(
                      selectedDate == null
                          ? 'Birthday'
                          : '${selectedDate?.year}/${selectedDate?.month}/${selectedDate?.day} ',
                      style: TextStyle(
                          fontSize: 16, fontWeight: FontWeight.w500),
                    ),
                  ),
                ),
              ),
            ),

showDatePicker(context) code

  DateTime? selectedDate;
  DateTime now = DateTime.now();

  void showDatePicker(BuildContext context) {
    DateTime initialDate = DateTime.now();
    DateTime minDate = DateTime(initialDate.year - 50, initialDate.month, initialDate.day);

    showCupertinoModalPopup(
      context: context,
      builder: (BuildContext builder) {
        return Container(
          height: MediaQuery.of(context).copyWith().size.height * 0.25,
          color: Colors.white,
          child: CupertinoDatePicker(
            maximumYear: initialDate.year,
            minimumYear: initialDate.year - 50,
            mode: CupertinoDatePickerMode.date,
            initialDateTime: initialDate,
            onDateTimeChanged: (value) {
              setState(() {
                selectedDate = value;
                // calAge();
              });
            },
            maximumDate: initialDate,
            minimumDate: minDate,
          ),
        );
      },
    );
  }

How to solve this?


Solution

  • This issue has an easy fix. When the picker function is called assign today's date to the selected date variable and then wait for the user's response on the picker, if the user changes the date it will update the data if not it will still update the state right after the user closes the picker

    Code : -

    Future<void> showDatePicker(BuildContext context) async { // <-- add async to this function
        DateTime initialDate = DateTime.now();
        selectedDate = initialDate;  // <-- add this line 
        DateTime minDate =
            DateTime(initialDate.year - 50, initialDate.month, initialDate.day);
    
        await showCupertinoModalPopup(  // <-- use await on this function
          context: context,
          builder: (BuildContext builder) {
            return Container(
              height: MediaQuery.of(context).copyWith().size.height * 0.25,
              color: Colors.white,
              child: CupertinoDatePicker(
                maximumYear: initialDate.year,
                minimumYear: initialDate.year - 50,
                mode: CupertinoDatePickerMode.date,
                initialDateTime: initialDate,
                onDateTimeChanged: (value) {
                  setState(() {
                    selectedDate = value;
                    // calAge();
                  });
                },
                maximumDate: initialDate,
                minimumDate: minDate,
              ),
            );
          },
        );
        setState(() {}); // <-- update the state
      }
    

    And to close the picker when the user taps on todays date, you have to wrap the Container widget with GestureDetector widget and pop the picker like this : -

    Future<void> showDatePicker(BuildContext context) async {
        
        DateTime initialDate = DateTime.now();
        selectedDate = initialDate; 
        DateTime minDate =
            DateTime(initialDate.year - 50, initialDate.month, initialDate.day);
    
        await showCupertinoModalPopup(
         
          context: context,
          builder: (BuildContext builder) {
            return GestureDetector( // <-- detect onTap with GestureDetector
              behavior: HitTestBehavior.translucent,
              onTap: () {
                Navigator.pop(context);
              },
              child: Container(
                height: MediaQuery.of(context).copyWith().size.height * 0.25,
                color: Colors.white,
                child: CupertinoDatePicker(
                  maximumYear: initialDate.year,
                  minimumYear: initialDate.year - 50,
                  mode: CupertinoDatePickerMode.date,
                  initialDateTime: initialDate,
                  onDateTimeChanged: (value) {
                    setState(() {
                      selectedDate = value;
                      // calAge();
                    });
                  },
                  maximumDate: initialDate,
                  minimumDate: minDate,
                ),
              ),
            );
          },
        );
        setState(() {}); 
      }