Select multiple dates in Android DatePickerDialog

Sravan Patti picture Sravan Patti · Jul 18, 2017 · Viewed 10.7k times · Source

I've got a requirement to select multiple dates from Android DatePickerDialog. Below is my snippet. With this, I'm able to select only one date. I've seen other libraries like https://github.com/square/android-times-square. But, I'm more interested in native Android code.

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val currentDate = Calendar.getInstance()
        val year = currentDate.get(Calendar.YEAR)
        val month = currentDate.get(Calendar.MONTH)
        val day = currentDate.get(Calendar.DAY_OF_MONTH)

        val maxDate = Calendar.getInstance()
        maxDate.add(Calendar.MONTH, 3)

        val datePickerDialog = DatePickerDialog(activity, onDateSet, year, month, day)
        datePickerDialog.datePicker.minDate = currentDate.timeInMillis
        datePickerDialog.datePicker.maxDate = maxDate.timeInMillis

        return datePickerDialog
}

Answer

Rakesh Yadav picture Rakesh Yadav · Aug 8, 2017

Android doesn't support this feature by till date. You can however create you own calendar. I have the same requirement and have done this. Please note that I have not allowed user to select any date. But users can select custom dates. I have created a Fragment which only changes months, and so it changes the adapter as when month is changed.

public class CalendarFragment extends DialogFragment {

private final String TAG = CalendarFragment.class.getSimpleName();

private static CalendarFragment instance;
private View view;
private ImageView ivDecrementMonth, ivIncrementMonth;
private TextView btnOk, btnCancel;
public TextView tvMonthYear;
private int counter = 0;
private int year = 2017;
private static CalendarActivity INSTANCE;

private Calendar calendarMinimumDate, calendarMaximumDate;

private GridView gridCalendarView;
private ArrayList<EventDateSelectionBean> listEventDates;
private String from;

public static final String KEY_EVENT_DATES = "key event dates";
public static final String KEY_FROM = "key from";

public static final String FROM_ANNOUNCEMENT_ACTIVITY = "from announcement activity";
public static final String FROM_BOOKING_DIALOG = "from booking dialog";
private List<String> listMonths;

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    Dialog dialog = super.onCreateDialog(savedInstanceState);
    WindowManager.LayoutParams wlmp = dialog.getWindow().getAttributes();
    wlmp.gravity = Gravity.CENTER | Gravity.FILL_HORIZONTAL;
    wlmp.dimAmount = 0.0F;
    dialog.getWindow().setAttributes(wlmp);
    dialog.getWindow().setWindowAnimations(R.style.DialogTheme);
    dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
    dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
            WindowManager.LayoutParams.FLAG_FULLSCREEN);
    dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
    return dialog;
}
//End of onCreateDialog()

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    if (view == null) {
        instance = this;
        view = inflater.inflate(R.layout.activity_calendar, container);
        findViewsId();
        setData();
        setClickListeners();
    }

    LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();


    return view;
}
//End of onCreateView()

private void findViewsId() {

    ivDecrementMonth = (ImageView) view.findViewById(R.id.ivDecrementMonth);
    ivIncrementMonth = (ImageView) view.findViewById(R.id.ivIncrementMonth);
    gridCalendarView = (GridView) view.findViewById(R.id.calendar);
    tvMonthYear = (TextView) view.findViewById(R.id.tvMonthYear);
    btnOk = (TextView) view.findViewById(R.id.btnOk);
    btnCancel = (TextView) view.findViewById(R.id.btnCancel);

}
//End of findViewsId()

private void setData() {
    listMonths = Arrays.asList(getResources().getStringArray(R.array.months));

    Bundle bundle = getArguments();

    calendarMinimumDate = Calendar.getInstance();
    calendarMinimumDate.setTimeInMillis(System.currentTimeMillis());
    calendarMaximumDate = Calendar.getInstance();
    calendarMaximumDate.setTimeInMillis(System.currentTimeMillis());

    btnOk.setText(getString(R.string.ok));
    btnCancel.setText(getString(R.string.cancel));

    listEventDates = bundle.getParcelableArrayList(KEY_EVENT_DATES);
    from = bundle.getString(KEY_FROM);

    //setMinMaxDateCalendar();

    counter = calendarMinimumDate.get(Calendar.MONTH);
    year = calendarMinimumDate.get(Calendar.YEAR);
    tvMonthYear.setText(listMonths.get(counter) + " " + year);

    MyCalendarAdapter adapter = new MyCalendarAdapter(GoToTourActivity.getInstance(),
            listEventDates, counter, year);
    gridCalendarView.setAdapter(adapter);
}
//End of setData()

private void setClickListeners() {
    btnOk.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (from.equals(FROM_ANNOUNCEMENT_ACTIVITY)) {
                GoToTourActivity.getInstance().setDate(listEventDates);
            } else if (from.equals(FROM_BOOKING_DIALOG)) {
                BookDialogs.getInstance().setDate(listEventDates);
            }
            dismiss();
        }
    });

    btnCancel.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            dismiss();
        }
    });

    ivDecrementMonth.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (counter == 0) {
                counter = listMonths.size() - 1;
                year = year - 1;
            } else {
                counter--;
            }
            tvMonthYear.setText(listMonths.get(counter) + " " + year);
            updateCalendar();
        }
    });

    ivIncrementMonth.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (counter == (listMonths.size() - 1)) {
                counter = 0;
                year = year + 1;
            } else {
                counter++;
            }
            tvMonthYear.setText(listMonths.get(counter) + " " + year);
            updateCalendar();
        }
    });
}
//End of setClickListeners()

private void updateCalendar() {
    MyCalendarAdapter adapter = new MyCalendarAdapter(GoToTourActivity.getInstance(),
            listEventDates, counter, year);
    gridCalendarView.setAdapter(adapter);
}
//End of updateCalendar()

}

//Here is the layout of Fragment Calendar

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/mainlayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="1">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="0.1"
    android:background="#FFF"
    android:gravity="center"
    android:orientation="horizontal"
    android:weightSum="1">

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="0.2"
        android:background="#FFF"
        android:gravity="center"
        android:orientation="horizontal">

        <LinearLayout
            android:id="@+id/llPrev"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="@dimen/margin">

            <ImageButton
                android:id="@+id/back"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="2dp"
                android:padding="1dp"
                android:src="@drawable/slide_right" />

        </LinearLayout>

    </LinearLayout>

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="0.6"
        android:gravity="center">

        <TextView
            android:id="@+id/tvMonthYear"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="DECEMBER 2017"
            android:textAllCaps="false"
            android:textColor="#000"
            android:textSize="22dp" />
    </LinearLayout>


    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="0.2"
        android:background="#FFF"
        android:gravity="center"
        android:orientation="horizontal">

        <LinearLayout
            android:id="@+id/llNext"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="@dimen/margin">

            <ImageButton
                android:id="@+id/forw"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="2dp"
                android:padding="1dp"
                android:rotation="180"
                android:src="@drawable/slide_right" />

        </LinearLayout>

    </LinearLayout>

</LinearLayout>

<LinearLayout
    android:id="@+id/llcalender"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="0.9"
    android:background="#FFF">

    <GridView
        android:id="@+id/calgrid"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:numColumns="7">

    </GridView>
</LinearLayout>

And the most important part is the Gridview Adapter. Go through the code and try to understand, there is not anything that would trouble you. However if you have any problem. Please comment.

public MyCalendarAdapter(Context context, ArrayList<EventDateSelectionBean> listEvents, int month, int year) {
    super();
    this._context = context;
    dateDefaultTextColor = context.getResources().getColor(R.color.calendar_date_default_text_color);
    dateInEventTextColor = context.getResources().getColor(R.color.calendar_date_in_event_text_color);
    dateInEventSelectedTextColor = context.getResources().getColor(R.color.calendar_date_in_event_selected_text_color);

    this.list = new ArrayList<>();
    Calendar calendar = Calendar.getInstance();
    setCurrentDayOfMonth(calendar.get(Calendar.DAY_OF_MONTH));
    setCurrentWeekDay(calendar.get(Calendar.DAY_OF_WEEK));
    this.listEvents = listEvents;

    currentMonth = month;
    currentYear = year;

    // Print Month
    printMonth(month, year);

    eventCalendar = Calendar.getInstance();
    eventCalendar.setTimeInMillis(System.currentTimeMillis());
    currentDayCalendar = Calendar.getInstance();
    currentDayCalendar.setTimeInMillis(System.currentTimeMillis());

    currentDayCalendar.set(Calendar.MONTH, currentMonth);
    currentDayCalendar.set(Calendar.YEAR, currentYear);
}

private String getMonthAsString(int i) {
    return months[i];
}

private int getNumberOfDaysOfMonth(int i) {
    if (currentYear % 4 == 0 && i == 1) {
        return daysOfMonth[i] + 1;
    } else {
        return daysOfMonth[i];
    }
}

public String getItem(int position) {
    return list.get(position);
}

@Override
public int getCount() {
    return list.size();
}

private void printMonth(int mm, int yyyy) {
    int trailingSpaces = 0;
    int daysInPrevMonth = 0;
    int prevMonth = 0;
    int prevYear = 0;
    int nextMonth = 0;
    int nextYear = 0;

    int currentMonth = mm/* - 1*/;
    daysInMonth = getNumberOfDaysOfMonth(currentMonth);

    // Gregorian Calendar : MINUS 1, set to FIRST OF MONTH
    GregorianCalendar cal = new GregorianCalendar(yyyy, currentMonth, 1);

    if (currentMonth == 11) {
        prevMonth = currentMonth - 1;
        daysInPrevMonth = getNumberOfDaysOfMonth(prevMonth);
        nextMonth = 0;
        prevYear = yyyy;
        nextYear = yyyy + 1;
    } else if (currentMonth == 0) {
        prevMonth = 11;
        prevYear = yyyy - 1;
        nextYear = yyyy;
        daysInPrevMonth = getNumberOfDaysOfMonth(prevMonth);
        nextMonth = 1;
    } else {
        prevMonth = currentMonth - 1;
        nextMonth = currentMonth + 1;
        nextYear = yyyy;
        prevYear = yyyy;
        daysInPrevMonth = getNumberOfDaysOfMonth(prevMonth);
    }

    int currentWeekDay = cal.get(Calendar.DAY_OF_WEEK) - 1;
    trailingSpaces = currentWeekDay;

    // Trailing Month days
    for (int i = 0; i < trailingSpaces; i++) {
        list.add(String.valueOf((daysInPrevMonth - trailingSpaces + DAY_OFFSET) + i) + "-GREY" + "-" + getMonthAsString(prevMonth) + "-" + prevYear);
    }

    // Current Month Days
    for (int i = 1; i <= daysInMonth; i++) {
        if (i == getCurrentDayOfMonth())
            list.add(String.valueOf(i) + "-BLUE" + "-" + getMonthAsString(currentMonth) + "-" + yyyy);
        else
            list.add(String.valueOf(i) + "-WHITE" + "-" + getMonthAsString(currentMonth) + "-" + yyyy);
    }

    // Leading Month days
    for (int i = 0; i < list.size() % 7; i++) {
        list.add(String.valueOf(i + 1) + "-GREY" + "-" + getMonthAsString(nextMonth) + "-" + nextYear);
    }
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    //Blue - Current Day
    //White - Current Month
    //Grey - Next Month
    final ViewHolder holder;
    if (convertView == null) {
        LayoutInflater inflater = (LayoutInflater) _context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = inflater.inflate(R.layout.calendar_day_gridcell, parent, false);
        holder = new ViewHolder(convertView);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    // ACCOUNT FOR SPACING
    String[] day_color = list.get(position).split("-");
    String theday = day_color[0];

    // Set the Day GridCell
    holder.btnDate.setText(theday);

    if (day_color[1].equals("WHITE") || day_color[1].equals("BLUE")) {      //For Current Month
        holder.btnDate.setTextColor(dateDefaultTextColor);
        holder.btnDate.setBackgroundResource(R.drawable.date_default_bg);

        currentDayCalendar.set(Calendar.DAY_OF_MONTH, Integer.valueOf(theday));

        for (int i = 0; i < listEvents.size(); i++) {

            EventDateSelectionBean eventDate = listEvents.get(i);
            setDataInEventCalendar(eventDate.getDate());

            if(Commons.checkDateEquality(currentDayCalendar, eventCalendar)) {

                final EventDateSelectionBean finalEventDate = eventDate;
                if(finalEventDate.isSelected()) {
                    holder.btnDate.setBackgroundResource(R.drawable.date_selected_bg);
                    holder.btnDate.setTextColor(dateInEventSelectedTextColor);

                } else {
                    holder.btnDate.setBackgroundResource(R.drawable.date_unselected);
                    holder.btnDate.setTextColor(dateInEventTextColor);
                }

                holder.btnDate.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        if(finalEventDate.isSelected()) {
                            finalEventDate.setSelected(false);
                            holder.btnDate.setBackgroundResource(R.drawable.date_unselected);
                            holder.btnDate.setTextColor(dateInEventTextColor);

                        } else {
                            finalEventDate.setSelected(true);
                            holder.btnDate.setBackgroundResource(R.drawable.date_selected_bg);
                            holder.btnDate.setTextColor(dateInEventSelectedTextColor);
                        }
                    }
                });
                break;
            }
        }
    } else {       //For Previous and next month dates
        holder.btnDate.setAlpha(0.4f);
        holder.btnDate.setBackgroundResource(R.drawable.date_default_bg);
        //holder.btnDate.setVisibility(View.INVISIBLE);
        holder.llBtnParent.setVisibility(View.INVISIBLE);
    }

    if (position == list.size() - 1) {
        //Set Default data
    }
    return convertView;
}
//End of getView()

public class ViewHolder {
    Button btnDate;
    LinearLayout llBtnParent;

    public ViewHolder(View view) {
        btnDate = (Button) view.findViewById(R.id.calendar_day_gridcell);
        llBtnParent = (LinearLayout) view.findViewById(R.id.llBtnParent);
    }
}

public int getCurrentDayOfMonth() {
    return currentDayOfMonth;
}

private void setCurrentDayOfMonth(int currentDayOfMonth) {
    this.currentDayOfMonth = currentDayOfMonth;
}

public void setCurrentWeekDay(int currentWeekDay) {
    this.currentWeekDay = currentWeekDay;
}

private void setDataInEventCalendar(String date) {
    String splittedDate[] = date.split("-");
    eventCalendar.set(Calendar.YEAR, Integer.valueOf(splittedDate[0]));
    eventCalendar.set(Calendar.MONTH, (Integer.valueOf(splittedDate[1]) - 1));
    eventCalendar.set(Calendar.DAY_OF_MONTH, Integer.valueOf(splittedDate[2]));

}
//End of setDataInEventCalendar()

}

Adapter layout is

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_margin="1dp"
android:background="@android:color/transparent"
android:id="@+id/llBtnParent">

<LinearLayout
    android:layout_width="44dp"
    android:layout_height="44dp"
    android:layout_margin="1dp"
    android:background="@drawable/day_calendar"
    android:padding="1dp"
    android:gravity="center">

    <com.yaashvi.placeandpeople.customviews.AttendanceButton
        android:id="@+id/calendar_day_gridcell"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:text="1"
        android:gravity="left"
        android:paddingLeft="2dp"
        android:textSize="12sp"/>
</LinearLayout>

The Output will be like that.

enter image description here