Multiple DatePickers in same activity

Viewed 48574

I am absolutely new to the Android platform and have been building an application while learning the development process.

Currently, I am working on an activity in which i need to deploy 2 date pickers. One is a "Start Date" and the other is an "End date". I have been following the DatePicker tutorial on the android developers page here: http://developer.android.com/resources/tutorials/views/hello-datepicker.html

For one DatePicker, it works just fine.

Now my problem is, when I replicate the whole process for a second date picker, it shows up just fine on the emulator as well as on the handset. But when no matter which button I press to select the dates, only the first TextView is updated and the second TextView keeps showing the current date.

Here is the code:

package com.datepicker;

import java.util.Calendar;

import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.TextView;

public class datepicker extends Activity {

private TextView mDateDisplay;
private TextView endDateDisplay;
private Button mPickDate;
private Button endPickDate;
private int mYear;
private int mMonth;
private int mDay;

static final int START_DATE_DIALOG_ID = 0;
static final int END_DATE_DIALOG_ID = 0;


/** Called when the activity is first created. */
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    /*  capture our View elements for the start date function   */
    mDateDisplay = (TextView) findViewById(R.id.startdateDisplay);
    mPickDate = (Button) findViewById(R.id.startpickDate);

    /* add a click listener to the button   */
    mPickDate.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            showDialog(START_DATE_DIALOG_ID);
        }
    });

    /* get the current date */
    final Calendar c = Calendar.getInstance();
    mYear = c.get(Calendar.YEAR);
    mMonth = c.get(Calendar.MONTH);
    mDay = c.get(Calendar.DAY_OF_MONTH);

    /* display the current date (this method is below)  */
    updateStartDisplay();


 /* capture our View elements for the end date function */
    endDateDisplay = (TextView) findViewById(R.id.enddateDisplay);
    endPickDate = (Button) findViewById(R.id.endpickDate);

    /* add a click listener to the button   */
    endPickDate.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            showDialog(END_DATE_DIALOG_ID);
        }
    });

    /* get the current date */
    final Calendar c1 = Calendar.getInstance();
    mYear = c1.get(Calendar.YEAR);
    mMonth = c1.get(Calendar.MONTH);
    mDay = c1.get(Calendar.DAY_OF_MONTH);

    /* display the current date (this method is below)  */
    updateEndDisplay();
}



private void updateEndDisplay() {
    endDateDisplay.setText(
            new StringBuilder()
                // Month is 0 based so add 1
                .append(mMonth + 1).append("-")
                .append(mDay).append("-")
                .append(mYear).append(" "));

}



private void updateStartDisplay() {
    mDateDisplay.setText(
            new StringBuilder()
                // Month is 0 based so add 1
                .append(mMonth + 1).append("-")
                .append(mDay).append("-")
                .append(mYear).append(" "));


}

/* the callback received when the user "sets" the date in the dialog for the start date function */

 private DatePickerDialog.OnDateSetListener mDateSetListener =
            new DatePickerDialog.OnDateSetListener() {

            public void onDateSet(DatePicker view, int year, 
                                  int monthOfYear, int dayOfMonth) {
                mYear = year;
                mMonth = monthOfYear;
                mDay = dayOfMonth;
                updateStartDisplay();
            }
        };

@Override
protected Dialog onCreateDialog(int id) {
    switch (id) {
    case START_DATE_DIALOG_ID:
        return new DatePickerDialog(this,
                    mDateSetListener,
                    mYear, mMonth, mDay);
    }
    return null;
}
/* the callback received when the user "sets" the date in the dialog for the end date function  */

private DatePickerDialog.OnDateSetListener endDateSetListener =
        new DatePickerDialog.OnDateSetListener() {

            public void onDateSet(DatePicker view, int year, 
                                  int monthOfYear, int dayOfMonth) {
                mYear = year;
                mMonth = monthOfYear;
                mDay = dayOfMonth;
                updateStartDisplay();
            }
        };

protected Dialog onCreateDialog1(int id) {
    switch (id) {
    case END_DATE_DIALOG_ID:
        return new DatePickerDialog(this,
                    endDateSetListener,
                    mYear, mMonth, mDay);
    }
    return null;
}

}

Please advise on the changes required for the code.

14 Answers

simply make boolean variable in mainActivity like this ::

private boolean startDateOrEndDAte = true;

then make the listeners for the buttons like this like this and make the value of the variable change for evrey button::

DialogFragment datePicker = new DatePickerFragment();

attendDate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                datePicker.show(getSupportFragmentManager(),"Date Picker");
                startOrEnd = true ;
            }
        });
        leaveDate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                datePicker.show(getSupportFragmentManager(),"Date Picker");
                startOrEnd = false ;
            }
        });

then in onDateSet methode just add if statment like this ::

public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {



    Calendar c = Calendar.getInstance();
    c.set(Calendar.YEAR, year);
    c.set(Calendar.MONTH, month);
    c.set(Calendar.DAY_OF_MONTH, dayOfMonth);
    String date = DateFormat.getDateInstance().format(c.getTime());
    attendDate = findViewById(R.id.attend_date);
    leaveDate = findViewById(R.id.leave_date);

    if (startOrEnd) {
        attendDate.setText(date);
    } else {
        leaveDate.setText(date);
    }
}

I make use of the DialogFragment tag to distinguish between instances of the DatePickerFragment in my activity. It works well and keeps things simple. This way you can reuse the same DatePickerFragment class and have numerous instances on your activity, set apart by the unique tag used for each.

The DatePickerFragment class is straight forward as per Android Dev documentation with an added interface which the activity has to implement. This allows the DatePickerFragment to call back to the activity, passing a Date object and identifying tag back.

Android Pickers

public class DatePickerFragment extends DialogFragment
  implements DatePickerDialog.OnDateSetListener {

  public interface DatePickerWithTagListener {
    public void onDateSet(String tag, Date date);
  }

  private static final String ARG_YEAR = "paramYear";
  private static final String ARG_MONTH = "paramMonth";
  private static final String ARG_DAY = "paramDay";

  private int mParamYear;
  private int mParamMonth;
  private int mParamDay;

  private Activity mActivity;
  private DatePickerFragment.DatePickerWithTagListener mListener;

  public DatePickerFragment() {
    // Required empty public constructor
  }

  /**
   * Use this factory method to create a new instance of
   * this fragment using the provided parameters.
   *
   * @param paramYear Year parameter.
   * @param paramMonth Month parameter.
   * @param paramDay Day parameter.
   * @return A new instance of fragment DatePickerFragment.
   */
  public static DatePickerFragment newInstance(int paramYear, int paramMonth, int paramDay) {
    DatePickerFragment fragment = new DatePickerFragment();
    Bundle args = new Bundle();
    args.putInt(ARG_YEAR, paramYear);
    args.putInt(ARG_MONTH, paramMonth);
    args.putInt(ARG_DAY, paramDay);
    fragment.setArguments(args);
    return fragment;
  }

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
      mParamYear = getArguments().getInt(ARG_YEAR);
      mParamMonth = getArguments().getInt(ARG_MONTH);
      mParamDay = getArguments().getInt(ARG_DAY);
    }
  }

  @Override
  public void onAttach(@NonNull Context context) {
    super.onAttach(context);
    mActivity = (Activity) context;

    try {
      mListener = (DatePickerFragment.DatePickerWithTagListener) mActivity;
    } catch (ClassCastException e) {
      throw new ClassCastException(mActivity.getClass().getName() + " must implement DatePickerWithTagListener");
    }
  }

  @NonNull
  @Override
  public DatePickerDialog onCreateDialog(@Nullable Bundle savedInstanceState) {
    // Create a new instance of DatePickerDialog and return it
    return new DatePickerDialog(mActivity, R.style.MyAlertDialog, this, mParamYear, mParamMonth, mParamDay);
  }

  /**
   * @param view       the picker associated with the dialog
   * @param year       the selected year
   * @param month      the selected month (0-11 for compatibility with
   *                   {@link Calendar#MONTH})
   * @param dayOfMonth the selected day of the month (1-31, depending on
   */
  @Override
  public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
    Date date = null;
    Calendar cal = Calendar.getInstance();

    cal.set(Calendar.YEAR, year);
    cal.set(Calendar.MONTH, month);
    cal.set(Calendar.DAY_OF_MONTH, dayOfMonth);
    date = cal.getTime();

    mListener.onDateSet(this.getTag(), date);
  }
}

Your activity needs to implement DatePickerFragment.DatePickerWithTagListener.

public class SelectFilterActivity extends AppCompatActivity
 implements DatePickerFragment.DatePickerWithTagListener {
  private static final String START_DATE_PICKER = "startDatePicker";
  private static final String END_DATE_PICKER = "endDatePicker";

....

private void setupStartDateClick() {
    binding.startDateTV.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        if (binding.useDateRange.isChecked()) {
          Calendar cal = Calendar.getInstance();
          cal.setTime(mFilter.getDateRangeStart());
          int year = cal.get(Calendar.YEAR);
          int month = cal.get(Calendar.MONTH);
          int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
          DialogFragment newFragment = DatePickerFragment.newInstance(year, month, dayOfMonth);
          newFragment.show(getSupportFragmentManager(), START_DATE_PICKER);
        }
      }
    });
  }

  private void setupEndDateClick() {
    binding.endDateTV.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        if (binding.useDateRange.isChecked()) {
          Calendar cal = Calendar.getInstance();
          cal.setTime(mFilter.getDateRangeStart());
          int year = cal.get(Calendar.YEAR);
          int month = cal.get(Calendar.MONTH);
          int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
          DialogFragment newFragment = DatePickerFragment.newInstance(year, month, dayOfMonth);
          newFragment.show(getSupportFragmentManager(), END_DATE_PICKER);
        }
      }
    });
  }

   
  @Override
  public void onDateSet(String tag, Date date) {
    if (tag.equals(START_DATE_PICKER)) {
      // do whatever you need to with the date returned for the start date picker
    }
    else if (tag.equals(END_DATE_PICKER)) {
      // do whatever you need to with the date returned for the end date picker
    }
  }

I was not satisfied with any of the aforementioned solutions so I made my own as follows: https://gist.github.com/JoachimR/f82b2b371b1ced4a09918c970e045d4f

import android.app.DatePickerDialog
import android.app.Dialog
import android.os.Bundle
import android.support.v4.app.DialogFragment
import java.util.*


class ChooseDayDialog : DialogFragment() {

    companion object {

        private val KEY_INITIAL_TIMESTAMP = "KEY_INITIAL_TIMESTAMP"
        private val KEY_REQUEST_CODE = "KEY_REQUEST_CODE"

        private val DEFAULT_REQUEST_CODE = 20

        fun createInstance(initialTimestamp: Long,
                           requestCode: Int = DEFAULT_REQUEST_CODE) =
                ChooseDayDialog().apply {
                    arguments = Bundle().apply {
                        putLong(KEY_INITIAL_TIMESTAMP, initialTimestamp)
                        putInt(KEY_REQUEST_CODE, requestCode)
                    }
                }

    }

    interface OnDayChosenListener {

        fun onDayChosen(requestCode: Int, year: Int, month: Int, dayOfMonth: Int)

    }

    private lateinit var listener: OnDayChosenListener

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val activity = activity
        if (activity is OnDayChosenListener) {
            listener = activity
        } else {
            throw IllegalStateException("Activity must implement OnDayChosenListener")
        }
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val timestamp = arguments?.getLong(KEY_INITIAL_TIMESTAMP, -1L) ?: -1L
        if (timestamp == -1L) {
            throw IllegalStateException("no initial time given")
        }
        val requestCode = arguments?.getInt(KEY_REQUEST_CODE, DEFAULT_REQUEST_CODE)
                ?: DEFAULT_REQUEST_CODE

        val calendar = Calendar.getInstance().apply {
            timeInMillis = timestamp
        }
        return DatePickerDialog(activity,
                DatePickerDialog.OnDateSetListener { _, year, month, dayOfMonth ->
                    listener.onDayChosen(requestCode, year, month, dayOfMonth)
                },
                calendar.get(Calendar.YEAR),
                calendar.get(Calendar.MONTH),
                calendar.get(Calendar.DAY_OF_MONTH))
    }

}

I had to implement 2 date pickers for the starting date of a trip and an ending date of it. I used a boolean flag to know which text view to fill with the picked date from the date picker dialog. Below, a visual representation of the code.

public class AddTrip extends AppCompatActivity implements DatePickerDialog.OnDateSetListener {

    private boolean startOrEnd = true;
    private Button startDateBtn;
    private Button endDateBtn;
    private TextView startDateText;
    private TextView endDateText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_trip);

        initAll();

        startDateBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showDatePickerDialog();
                startOrEnd = true;
            }
        });

        endDateBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showDatePickerDialog();
                startOrEnd = false;
            }
        });
    }

    public void initAll(){
        startDateBtn = findViewById(R.id.idstartDateBtn);
        endDateBtn = findViewById(R.id.idendDateBtn);
        startDateText = findViewById(R.id.startDateText);
        endDateText = findViewById(R.id.endDateText);
    }


    private void showDatePickerDialog() {
        DatePickerDialog datePickerDialog = new DatePickerDialog(
                this,
                this,
                Calendar.getInstance().get(Calendar.YEAR),
                Calendar.getInstance().get(Calendar.MONTH),
                Calendar.getInstance().get(Calendar.DAY_OF_MONTH));
        datePickerDialog.show();
    }

    @Override
    public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
        String date = "month/day/year: " + month + "/" + dayOfMonth + "/" + year;
        if (startOrEnd) {
            startDateText.setText(date);
        } else {
            endDateText.setText(date);
        }
    }
}

Visual representation of my code

    issue.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Bundle bundle = new Bundle();
            bundle.putInt("DATE", 1);

            DialogFragment newFragment = new MyDatePickerFragment();
            newFragment.setArguments(bundle);
            newFragment.show(getSupportFragmentManager(), "datePicker");
        }
    });

    expiry.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Bundle bundle = new Bundle();
            bundle.putInt("DATE", 2);

            DialogFragment newFragment = new MyDatePickerFragment();
            newFragment.setArguments(bundle);
            newFragment.show(getSupportFragmentManager(), "datePicker");

        }
    });

}


@Override
public void sendInput(String input, int id) {
    date = input;
    switch (id) {
        case 1:
            issue.setText(date);
            break;
        case 2:
            expiry.setText(date);
            break;
    }




public class MyDatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {

    static final int ISSUE_DATE = 1;
    static final int EXPIRY_DATE = 2;

    private int mChosenDate;

    int cur = 0;


    @Override
    public void onDateSet(DatePicker datePicker, int year, int month, int day) {

        String date;
        if (cur == ISSUE_DATE) {
            // set selected date into textview

            Log.v("Date Issue", "Date1 : " + new StringBuilder().append(month + 1)
                    .append("-").append(day).append("-").append(year)
                    .append(" "));
            date = day + "/0" + (month + 1) + "/" + year;
        } else {
            Log.v("Date expiry", "Date2 : " + new StringBuilder().append(month + 1)
                    .append("-").append(day).append("-").append(year)
                    .append(" "));
            date = day + "/0" + (month + 1) + "/" + year;

        }
        listenerforActivity.sendInput(date, cur);
    }

    public interface OnDateSetListenerInterface {
        void sendInput(String input, int id);
    }

    public OnDateSetListenerInterface listenerforActivity;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            listenerforActivity = (OnDateSetListenerInterface) getActivity();
        } catch (ClassCastException e) {
            Toast.makeText(context, e.toString(), Toast.LENGTH_SHORT).show();
        }
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        // Use the current date as the default date in the picker
        final Calendar c = Calendar.getInstance();
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH);
        int day = c.get(Calendar.DAY_OF_MONTH);


        Bundle bundle = this.getArguments();
        if (bundle != null) {
            mChosenDate = bundle.getInt("DATE", 1);
        }


        switch (mChosenDate) {

            case ISSUE_DATE:
                cur = ISSUE_DATE;
                return new DatePickerDialog(getActivity(), this, year, month, day);

            case EXPIRY_DATE:
                cur = EXPIRY_DATE;
                return new DatePickerDialog(getActivity(), this, year, month, day);

        }
        return null;
    }


}

My solution for this was simply using a switch

public class RegisterActivity extends AppCompatActivity implements DatePickerDialog.OnDateSetListener {
private TextView mDisplayBirthDay;
private TextView mDisplayExpDate;
private TextView mDisplayIssueDate;
private int sw;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_register);
    Toolbar toolbar = findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    Objects.requireNonNull(getSupportActionBar()).setDisplayShowTitleEnabled(false); // to get rid of the title of the activity
    Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);

    mDisplayBirthDay = findViewById(R.id.birthDate);
    findViewById(R.id.birthDate).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            showDatePickerDialog();
            sw = 0;
        }
    });
    mDisplayExpDate = findViewById(R.id.editText_expire);
    findViewById(R.id.editText_expire).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            showDatePickerDialog();
            sw = 1;
        }
    });
    mDisplayIssueDate = findViewById(R.id.editText_issueDate);
    findViewById(R.id.editText_issueDate).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            showDatePickerDialog();
            sw = 2;
        }
    });
}
private  void showDatePickerDialog(){
    DatePickerDialog datePickerDialog = new DatePickerDialog(this,
            this,
            Calendar.getInstance().get(Calendar.YEAR),
            Calendar.getInstance().get(Calendar.MONTH),
            Calendar.getInstance().get(Calendar.DAY_OF_MONTH));
    datePickerDialog.show();
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.show_registrations:
            getSupportFragmentManager().beginTransaction().replace(R.id.event_description,
                    //TODO: pass eventID as intend when clicked on event
                    EventRegistration.newInstance(69)).commit();
            break;
        case R.id.visibility_event:

            break;
        case android.R.id.home:
            onBackPressed(); //handling the "back" button
            break;
        default:
    }
    return true;
}

@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
    month = month + 1;  //because January is the month 0
    String date = dayOfMonth + "/" + month + "/" + year;
    switch (sw){
        case 0:
            mDisplayBirthDay.setText(date);
            break;
        case 1:
            mDisplayExpDate.setText(date);
            break;
        case 2:
            mDisplayIssueDate.setText(date);
            break;
        default:
    }

}

}

I solved this problem by passing a flag id to the DialogFragment and then onDateSet make use of the flag to set the textview data accordingly

Here is the code portion for Dialog Fragment:

public class twodatepickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener{
private int first ;

public twodatepickerFragment(int i) {
    first=i;
}

@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
    int date=c.get( Calendar.DAY_OF_MONTH);
    int month= c.get( Calendar.MONTH);
    int year=c.get ( Calendar.YEAR );
    return new DatePickerDialog(getActivity(),(DatePickerDialog.OnDateSetListener) getActivity (), year, month, date);
    return new DatePickerDialog(getActivity(),this, year, month, date);
}
@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
    calendar.set(Calendar.YEAR, year);
    calendar.set(Calendar.MONTH, month);
    calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);

    Date date = calendar.getTime();
    TextView textView = findViewById(R.id.date_selected);
    textView.setText(new SimpleDateFormat("dd-MMMM-yyyy").format(date));
    if(first==0){
        TextView tv= getActivity().findViewById(R.id.date_selected);
        tv.setText(new SimpleDateFormat("dd-MMMM-yyyy").format(date));
    }else{
        TextView tv= getActivity().findViewById(R.id.date_selected_2);
        tv.setText(new SimpleDateFormat("dd-MMMM-yyyy").format(date));
    }
}

}

Here is the code for MainActivity, here select_date_1 and select_date_2 are button.

 select_date_2.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            DialogFragment datepicker = new twodatepickerFragment (1);
            datepicker.show ( getSupportFragmentManager (),"date picker" );
        }
    });
    select_date_1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            DialogFragment datepicker = new twodatepickerFragment (0);
            datepicker.show ( getSupportFragmentManager (),"date picker" );
        }
    });
Related