'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,
              ),
            ),


Solution 1:[1]

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,
        ),
      ),
    ),
  ),
);

Solution 2:[2]

You can wrap your TextField with AbsorbPointer , so your widget tree would look something like this:

GestureDetector(
  onTap:()=>showDialog(),
  child:AbsorbPointer(
    child: MyTextField(),
  )
)

Solution 3:[3]

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.

Solution 4:[4]

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

enter image description here

enter image description here

enter image description here

Solution 5:[5]

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);
    }
  },
),

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 novas1r1
Solution 2 Shady Aziza
Solution 3 Shourya Shikhar
Solution 4 Quick learner
Solution 5 Robert Christopher