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
}
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.