Skip to content

Instantly share code, notes, and snippets.

@resengupta
Last active October 15, 2015 06:04
Show Gist options
  • Save resengupta/83e70fdf26b7858a85f7 to your computer and use it in GitHub Desktop.
Save resengupta/83e70fdf26b7858a85f7 to your computer and use it in GitHub Desktop.
Date picker modified... which allows the user to select month and year (Without the day)
import android.view.View;
import android.widget.NumberPicker;
import com.myapp.android.us.R;
import java.text.DateFormatSymbols;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Locale;
/**
* A delegate implementing the simple Date Picker functionality and takes care of the spinner UI.
*/
public class SimpleDatePickerDelegate {
private static final int DEFAULT_START_YEAR = 1900;
private static final int DEFAULT_END_YEAR = 2100;
private final NumberPicker mMonthSpinner;
private final NumberPicker mYearSpinner;
private Calendar mTempDate;
private Calendar mCurrentDate;
private Calendar mMinDate;
private Calendar mMaxDate;
private String[] mShortMonths;
private int mNumberOfMonths;
private Locale mCurrentLocale;
private OnDateChangedListener mOnDateChangedListener;
public SimpleDatePickerDelegate(View parent) {
setCurrentLocale(Locale.getDefault());
NumberPicker.OnValueChangeListener onChangeListener = new NumberPicker
.OnValueChangeListener() {
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
// take care of wrapping of days and months to update greater fields
if (picker == mMonthSpinner) {
if (oldVal == 11 && newVal == 0) {
mTempDate.add(Calendar.MONTH, 1);
} else if (oldVal == 0 && newVal == 11) {
mTempDate.add(Calendar.MONTH, -1);
} else {
mTempDate.add(Calendar.MONTH, newVal - oldVal);
}
} else if (picker == mYearSpinner) {
mTempDate.set(Calendar.YEAR, newVal);
} else {
throw new IllegalArgumentException();
}
// now set the date to the adjusted one
setDate(mTempDate.get(Calendar.YEAR), mTempDate.get(Calendar.MONTH));
updateSpinners();
notifyDateChanged();
}
};
// month
mMonthSpinner = (NumberPicker) parent.findViewById(R.id.month);
mMonthSpinner.setMinValue(0);
mMonthSpinner.setMaxValue(mNumberOfMonths - 1);
mMonthSpinner.setDisplayedValues(mShortMonths);
mMonthSpinner.setOnLongPressUpdateInterval(200);
mMonthSpinner.setOnValueChangedListener(onChangeListener);
// year
mYearSpinner = (NumberPicker) parent.findViewById(R.id.year);
mYearSpinner.setOnLongPressUpdateInterval(100);
mYearSpinner.setOnValueChangedListener(onChangeListener);
// set the min date giving priority of the minDate over startYear
mTempDate.clear();
mTempDate.set(DEFAULT_START_YEAR, 0, 1);
setMinDate(mTempDate.getTimeInMillis());
// set the max date giving priority of the maxDate over endYear
mTempDate.clear();
mTempDate.set(DEFAULT_END_YEAR, 11, 31);
setMaxDate(mTempDate.getTimeInMillis());
// initialize to current date
mCurrentDate.setTimeInMillis(System.currentTimeMillis());
init(mCurrentDate.get(Calendar.YEAR), mCurrentDate.get(Calendar.MONTH), null);
}
public void init(int year, int monthOfYear, OnDateChangedListener onDateChangedListener) {
setDate(year, monthOfYear);
updateSpinners();
mOnDateChangedListener = onDateChangedListener;
}
public void setMinDate(long minDate) {
mTempDate.setTimeInMillis(minDate);
if (mTempDate.get(Calendar.YEAR) == mMinDate.get(Calendar.YEAR)
&& mTempDate.get(Calendar.DAY_OF_YEAR) != mMinDate.get(Calendar.DAY_OF_YEAR)) {
return;
}
mMinDate.setTimeInMillis(minDate);
if (mCurrentDate.before(mMinDate)) {
mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
}
updateSpinners();
}
public void setMaxDate(long maxDate) {
mTempDate.setTimeInMillis(maxDate);
if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR)
&& mTempDate.get(Calendar.DAY_OF_YEAR) != mMaxDate.get(Calendar.DAY_OF_YEAR)) {
return;
}
mMaxDate.setTimeInMillis(maxDate);
if (mCurrentDate.after(mMaxDate)) {
mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
}
updateSpinners();
}
public int getYear() {
return mCurrentDate.get(Calendar.YEAR);
}
public int getMonth() {
return mCurrentDate.get(Calendar.MONTH);
}
/**
* Sets the current locale.
*
* @param locale The current locale.
*/
protected void setCurrentLocale(Locale locale) {
if (!locale.equals(mCurrentLocale)) {
mCurrentLocale = locale;
}
mTempDate = getCalendarForLocale(mTempDate, locale);
mMinDate = getCalendarForLocale(mMinDate, locale);
mMaxDate = getCalendarForLocale(mMaxDate, locale);
mCurrentDate = getCalendarForLocale(mCurrentDate, locale);
mNumberOfMonths = mTempDate.getActualMaximum(Calendar.MONTH) + 1;
mShortMonths = new DateFormatSymbols().getShortMonths();
if (usingNumericMonths()) {
// We're in a locale where a date should either be all-numeric, or all-text.
// All-text would require custom NumberPicker formatters for day and year.
mShortMonths = new String[mNumberOfMonths];
for (int i = 0; i < mNumberOfMonths; ++i) {
mShortMonths[i] = String.format("%d", i + 1);
}
}
}
private void setDate(int year, int month) {
mCurrentDate.set(Calendar.YEAR, year);
mCurrentDate.set(Calendar.MONTH, month);
if (mCurrentDate.before(mMinDate)) {
mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
} else if (mCurrentDate.after(mMaxDate)) {
mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
}
}
private void updateSpinners() {
// set the spinner ranges respecting the min and max dates
if (mCurrentDate.equals(mMinDate)) {
mMonthSpinner.setDisplayedValues(null);
mMonthSpinner.setMinValue(mCurrentDate.get(Calendar.MONTH));
mMonthSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.MONTH));
mMonthSpinner.setWrapSelectorWheel(false);
} else if (mCurrentDate.equals(mMaxDate)) {
mMonthSpinner.setDisplayedValues(null);
mMonthSpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.MONTH));
mMonthSpinner.setMaxValue(mCurrentDate.get(Calendar.MONTH));
mMonthSpinner.setWrapSelectorWheel(false);
} else {
mMonthSpinner.setDisplayedValues(null);
mMonthSpinner.setMinValue(0);
mMonthSpinner.setMaxValue(11);
mMonthSpinner.setWrapSelectorWheel(true);
}
// make sure the month names are a zero based array
// with the months in the month spinner
String[] displayedValues = Arrays.copyOfRange(
mShortMonths, mMonthSpinner.getMinValue(), mMonthSpinner.getMaxValue() + 1);
mMonthSpinner.setDisplayedValues(displayedValues);
// year spinner range does not change based on the current date
mYearSpinner.setMinValue(mMinDate.get(Calendar.YEAR));
mYearSpinner.setMaxValue(mMaxDate.get(Calendar.YEAR));
mYearSpinner.setWrapSelectorWheel(false);
// set the spinner values
mYearSpinner.setValue(mCurrentDate.get(Calendar.YEAR));
mMonthSpinner.setValue(mCurrentDate.get(Calendar.MONTH));
}
private boolean usingNumericMonths() {
return Character.isDigit(mShortMonths[Calendar.JANUARY].charAt(0));
}
/**
* Gets a calendar for locale bootstrapped with the value of a given calendar.
*
* @param oldCalendar The old calendar.
* @param locale The locale.
*/
private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) {
if (oldCalendar == null) {
return Calendar.getInstance(locale);
} else {
long currentTimeMillis = oldCalendar.getTimeInMillis();
Calendar newCalendar = Calendar.getInstance(locale);
newCalendar.setTimeInMillis(currentTimeMillis);
return newCalendar;
}
}
/**
* Notifies the listener, if such, for a change in the selected date.
*/
private void notifyDateChanged() {
if (mOnDateChangedListener != null) {
mOnDateChangedListener.onDateChanged(getYear(), getMonth());
}
}
/**
* The callback used to indicate the user changed the date.
*/
public interface OnDateChangedListener {
/**
* Called upon a date change.
*
* @param year The year that was set.
* @param monthOfYear The month that was set (0-11) for compatibility with {@link
* java.util.Calendar}.
*/
void onDateChanged(int year, int monthOfYear);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment