6

On my view I have a button which when pressed pops up a DatePickerDialog. The poppedup dialog has a "Done" button. When I press that button the selected date is populated into an EditText box.

Now, when I press the back button (Back button), it still populates the date in the EditText. How do I dismiss the dialog without returning any value from it.

This is code I've got-

The activity which invokes the fragment:

public class TransactionActivity extends FragmentActivity implements iRibbonMenuCallback {        
    .....
    public void selectDate(View view) { 
        // This is the method invoked by the button
        SelectDateFragment newFragment = new SelectDateFragment();
        newFragment.show(getSupportFragmentManager(), "DatePicker");
    }

    public void populateSetDate(int year, int month, int day) {
        // Puts the date in the EditText box
        mEdit = (EditText)findViewById(R.id.DateText);
        mEdit.setText(month+"/"+day+"/"+year);
    }
}

A fragment for the Dialog (based on this page on Android API guides):

public class SelectDateFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        final Calendar calendar = Calendar.getInstance();
        int yy = calendar.get(Calendar.YEAR);
        int mm = calendar.get(Calendar.MONTH);
        int dd = calendar.get(Calendar.DAY_OF_MONTH);
        return new DatePickerDialog(getActivity(), this, yy, mm, dd);
    }

    public void onDateSet(DatePicker view, int yy, int mm, int dd) {
             // Calls a method on the activity which invokes this fragment
         ((TransactionActivity)getActivity()).populateSetDate(yy, mm+1, dd);    

    }
}

There doesn't seem to be a method analogous with onDataSet for handling the case when data was not set.

Is there a way to cancel/dismiss the popped up datepicker without getting it's value?

Thanks.

Bharat
  • 2,960
  • 2
  • 38
  • 57

8 Answers8

6

It looks like there is a bug with Jelybean where the Cancel button isn't working(& hence the back button). This is discussed in Jelly Bean DatePickerDialog --- is there a way to cancel?

David Cesarino, who reported the bug and workaround in the above post, posted his solution here and SO.

cavega slightly modified the above solution to allow initialization of the date in the DatePickerDialog to something other than today's date. Code can be found here. I used his solution and got it to work.

Community
  • 1
  • 1
Bharat
  • 2,960
  • 2
  • 38
  • 57
3

I wrote simple successor of standard DatePickerDialog that works fine for me:

/**
 * Enhanced date picker dialog. Main difference from ancestor is that it calls
 * OnDateSetListener only when when pressing OK button, and skips event when closing with
 * BACK key or by tapping outside a dialog.
 */
public class IBSDatePickerDialog extends DatePickerDialog {

    public IBSDatePickerDialog(final Context context, final OnDateSetListener callBack, final int year, final int monthOfYear, final int dayOfMonth) {
        super(context, callBack, year, monthOfYear, dayOfMonth);
    }

    public IBSDatePickerDialog(final Context context, final int theme, final OnDateSetListener callBack, final int year, final int monthOfYear, final int dayOfMonth) {
        super(context, theme, callBack, year, monthOfYear, dayOfMonth);
    }

    @Override
    public void onClick(final DialogInterface dialog, final int which) {
        // Prevent calling onDateSet handler when clicking to dialog buttons other, then "OK"
        if (which == DialogInterface.BUTTON_POSITIVE)
            super.onClick(dialog, which);
    }

    @Override
    protected void onStop() {
        // prevent calling onDateSet handler when stopping dialog for whatever reason (because this includes
        // closing by BACK button or by tapping outside dialog, this is exactly what we try to avoid)

        //super.onStop();
    }
}

Using dialog example (free bonus: adding Cancel button to dialog for even better usability):

public static class datePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {

    @Override
    public Dialog onCreateDialog(final Bundle savedInstanceState) {

        Calendar cal = Calendar.getInstance();
        IBSDatePickerDialog dlg = new IBSDatePickerDialog(myActivity, this, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));

        // Add Cancel button into dialog
        dlg.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", (OnClickListener) null);

        return dlg;
    }

    @Override
    public void onDateSet(final DatePicker view, final int year, final int month, final int day) {
        // TODO: do whatever you want with date selected
    }
}

public void showDatePickerDialog() {
    final datePickerFragment f = new datePickerFragment();
    f.show(getSupportFragmentManager(), "datePicker");
}
Denys Avilov
  • 427
  • 1
  • 4
  • 8
3

I struggled with this also, but the solution is very simple. The DialogFragment implements the DialogInterface.OnCancelListener and DialogInterface.OnDismissListener and because DialogInterface.OnCancelListener.onCancel gets called before DialogInterface.OnDismissListener.onDismiss, you can clear the date values in onCancel and call the TransactionActivity.populateSetDate method in onDismiss only if the date values are not 0.

As an aside: to make the Fragment more standalone, it's good practice that the Fragment defines a public interface that the calling activity must implement, so you can call the populateSetDate method on the interface instead of the activity.

See your code below for implementation of the onCancel and onDismiss:

public class SelectDateFragment extends DialogFragment
  implements DatePickerDialog.OnDateSetListener
{

  private int year;
  private int month;
  private int day;

  @Override
  public Dialog onCreateDialog(Bundle savedInstanceState) {
    final Calendar calendar = Calendar.getInstance();
    int yy = calendar.get(Calendar.YEAR);
    int mm = calendar.get(Calendar.MONTH);
    int dd = calendar.get(Calendar.DAY_OF_MONTH);
    return new DatePickerDialog(getActivity(), this, yy, mm, dd);
  }

  public void onDateSet(DatePicker view, int yy, int mm, int dd) {
    // Calls a method on the activity which invokes this fragment
    // ((TransactionActivity)getActivity()).populateSetDate(yy, mm+1, dd); 
    year = yy;
    month = mm;
    day = dd;
  }

  // Gets called before onDismiss, so we can erase the selectedDate
  @Override
  public void onCancel(DialogInterface dialog) {
    year = 0;
    month = 0;
    day = 0;
  }


  @Override
  public void onDismiss(DialogInterface dialog) {
    if (year != 0) {
      ((TransactionActivity)getActivity()).populateSetDate(year, month + 1, day);
    }
  }
}
michielve
  • 514
  • 4
  • 16
1
public class pickerdate extends Activity {
/** Called when the activity is first created. */
  private TextView mDateDisplay;
    private Button mPickDate;
    private int mYear;
    private int mMonth;
    private int mDay;

    static final int DATE_DIALOG_ID = 0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);


        mDateDisplay = (TextView) findViewById(R.id.dateDisplay);
        mPickDate = (Button) findViewById(R.id.pickDate);


        mPickDate.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                showDialog(DATE_DIALOG_ID);
            }
        });


        final Calendar c = Calendar.getInstance();
        mYear = c.get(Calendar.YEAR);
        mMonth = c.get(Calendar.MONTH);
        mDay = c.get(Calendar.DAY_OF_MONTH);

        updateDisplay();
    }
    private void updateDisplay() {
        mDateDisplay.setText(
            new StringBuilder()
                    // Month is 0 based so add 1
                    .append(mMonth + 1).append("-")
                    .append(mDay).append("-")
                    .append(mYear).append(" "));
    }
    private DatePickerDialog.OnDateSetListener mDateSetListener =
        new DatePickerDialog.OnDateSetListener() {

            public void onDateSet(DatePicker view, int year, 
                                  int monthOfYear, int dayOfMonth) {
                mYear = year;
                mMonth = monthOfYear;
                mDay = dayOfMonth;
                updateDisplay();
            }
        };
        @Override
        protected Dialog onCreateDialog(int id) {
            switch (id) {
            case DATE_DIALOG_ID:
                return new DatePickerDialog(this,
                            mDateSetListener,
                            mYear, mMonth, mDay);
            }
            return null;
        }
 }

The above code worked for me. The dialog has set and cancel button. Set will set the date and cancel will dismiss dialog. Modify the same according to your needs. Clicking back button will also dismiss dialog.

Raghunandan
  • 132,755
  • 26
  • 225
  • 256
  • I am using fragments in my approach & I think, if I'm right that's the way to go for ICS & above.. – Bharat Mar 08 '13 at 07:38
  • You mean to say the above does not work in Fragments??. The above should work in fragments. I haven't tried. But it should work. I don't see any reason why this won't work n fragments. Some one else can you with this. – Raghunandan Mar 08 '13 at 07:44
0

I think you are asking for this

 setOnCancelListener(new OnCancelListener() {
                @Override
                public void onCancel(DialogInterface dialog) {
    }
DjHacktorReborn
  • 2,908
  • 2
  • 20
  • 29
  • This didn't seem to work. This is what I tried: `dialog.setOnKeyListener(new Dialog.OnKeyListener() { @Override public boolean onKey(DialogInterface arg0, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { dialog.dismiss(); } return false; } });` – Bharat Mar 08 '13 at 07:31
0

You could try include this in your alertDialog

If you cancel the dialog, mEdit will return as empty. mEdit.setText("");

 AlertDialog alertDialog;

    alertDialog.setOnCancelListener(new OnCancelListener() 
    {                   
           @Override
            public void onCancel(DialogInterface dialog) 
             {
               // TODO Auto-generated method stub
                    mEdit.setText(""); 
                    dialog.dismiss();                           

            }
});
IssacZH.
  • 1,457
  • 3
  • 24
  • 54
  • DatePickerDialog doesn't seem to have the method onCancel. This is what I have: `final DatePickerDialog dialog = new DatePickerDialog(getActivity(), this, yy, mm, dd); dialog.setOnCancelListener(new OnCancelListener() { ...}` I get `not applicable for the arguments` message on eclipse. – Bharat Mar 08 '13 at 07:35
  • My bad. I mistaken that with this. – IssacZH. Mar 08 '13 at 07:47
0

use following method, which is called when user presses Back button. This method is of Activity.

@Override
public void onBackPressed() {
    // TODO Auto-generated method stub
    super.onBackPressed();

    dialog.dismiss();
}
Chintan Rathod
  • 25,864
  • 13
  • 83
  • 93
  • I am having the DatePickerDialog in a Fragment class. `public class SelectDateFragment extends DialogFragment`. The onBackPressed() doesn't seem to have a method in the protocol for DialogFragment..Eclipse says `The method onBackPressed() of type SelectDateFragment must override or implement a supertype method` – Bharat Mar 08 '13 at 08:06
  • But there is a method in `FragmentActivity`. Don't you think so you can make a listener in `DialogFragment` and when activity get **Back** button pressed event, you fire a listener?? – Chintan Rathod Mar 08 '13 at 08:12
0

Instead of implementing custom DatePickerDialog, you can implement custom OnClickListener for positive button:

DatePickerDialog dateDialog = new DatePickerDialog(this, null, year, month, day);
datePickerDialog.setButton(DialogInterface.BUTTON_POSITIVE,
    getResources().getString(R.string.text_done),
    new OnDoneClickListener(datePickerDialog));

// <...>

private class OnDoneClickListener implements DialogInterface.OnClickListener {

        private DatePickerDialog mPickerDialog;

        BirthDatePickerDialog(DatePickerDialog mPickerDialog) {
            this.mPickerDialog = mPickerDialog;
        }

        @Override
        public void onClick(DialogInterface dialog, int which) {
            SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
            Calendar cal = Calendar.getInstance();
            DatePicker picker =  mPickerDialog.getDatePicker();
            cal.set(Calendar.YEAR, picker.getYear());
            cal.set(Calendar.MONTH, picker.getMonth());
            cal.set(Calendar.DAY_OF_MONTH, picker.getDayOfMonth());
            spinnerDateBirth.setText(dateFormat.format(cal.getTime()));
        }
}

Any of back or tap on empty area will dismiss the dialog with doing nothing.

a.toropov
  • 218
  • 2
  • 11