diff --git a/bottomsheetpickers/src/main/java/com/philliphsu/bottomsheetpickers/date/DatePickerController.java b/bottomsheetpickers/src/main/java/com/philliphsu/bottomsheetpickers/date/DatePickerController.java index d44a059..add8881 100644 --- a/bottomsheetpickers/src/main/java/com/philliphsu/bottomsheetpickers/date/DatePickerController.java +++ b/bottomsheetpickers/src/main/java/com/philliphsu/bottomsheetpickers/date/DatePickerController.java @@ -48,4 +48,6 @@ public interface DatePickerController { Calendar getMaxDate(); void tryVibrate(); + + void pickYear(); } diff --git a/bottomsheetpickers/src/main/java/com/philliphsu/bottomsheetpickers/date/DatePickerDialog.java b/bottomsheetpickers/src/main/java/com/philliphsu/bottomsheetpickers/date/DatePickerDialog.java index 195749c..04e6bdc 100644 --- a/bottomsheetpickers/src/main/java/com/philliphsu/bottomsheetpickers/date/DatePickerDialog.java +++ b/bottomsheetpickers/src/main/java/com/philliphsu/bottomsheetpickers/date/DatePickerDialog.java @@ -117,6 +117,7 @@ public class DatePickerDialog extends BottomSheetPickerDialog implements private int mHeaderTextColorUnselected; private int mDayOfWeekHeaderTextColorSelected; private int mDayOfWeekHeaderTextColorUnselected; + private boolean mPickDateWithoutDay = false; /** * The callback used to indicate the user is done filling in the date. @@ -158,6 +159,18 @@ public static DatePickerDialog newInstance(OnDateSetListener callBack, int year, return ret; } + /** + * @param callBack How the parent is notified that the date is set. + * @param year The initial year of the dialog. + * @param monthOfYear The initial month of the dialog. + */ + public static DatePickerDialog newInstance(OnDateSetListener callBack, int year, + int monthOfYear) { + DatePickerDialog ret = new DatePickerDialog(); + ret.initialize(callBack, year, monthOfYear, 1); + return ret; + } + void initialize(OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth) { mCallBack = callBack; mCalendar.set(Calendar.YEAR, year); @@ -255,7 +268,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, } final Activity activity = getActivity(); - mDayPickerView = new PagingDayPickerView(activity, this, mThemeDark, mAccentColor); + mDayPickerView = new PagingDayPickerView(activity, this, mThemeDark, mAccentColor, mPickDateWithoutDay); mYearPickerView = new YearPickerView(activity, this); mYearPickerView.setTheme(activity, mThemeDark); mYearPickerView.setAccentColor(mAccentColor); @@ -443,7 +456,7 @@ private void updateHeaderSelectedView(final int viewIndex) { * of the current locale. */ private void determineLocale_MD_Y_Indices() { - String formattedDate = formatMonthDayYear(mCalendar); + String formattedDate = formatMonthDayYear(mCalendar, mPickDateWithoutDay); // Get the (MD) and Y parts of the formatted date in the current locale, // so that we can compare their relative positions. // @@ -454,7 +467,7 @@ private void determineLocale_MD_Y_Indices() { // That is harder than it sounds. // Different locales use different year delimiters, and some don't use one at all. // For example, a fully formatted date in the French locale is "30 juin 2009". - String monthAndDay = formatMonthAndDay(mCalendar); + String monthAndDay = formatMonthAndDay(mCalendar, mPickDateWithoutDay); String year = extractYearFromFormattedDate(formattedDate, monthAndDay); // All locales format the M and D together; which comes @@ -468,13 +481,17 @@ private void determineLocale_MD_Y_Indices() { } } - private static String formatMonthDayYear(Calendar calendar) { + private static String formatMonthDayYear(Calendar calendar, boolean mPickDateWithoutDay) { int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH | DateUtils.FORMAT_SHOW_YEAR; + if (mPickDateWithoutDay) + flags |= DateUtils.FORMAT_NO_MONTH_DAY; return formatDate(calendar, flags); } - private static String formatMonthAndDay(Calendar calendar) { + private static String formatMonthAndDay(Calendar calendar, boolean mPickDateWithoutDay) { int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH | DateUtils.FORMAT_NO_YEAR; + if (mPickDateWithoutDay) + flags |= DateUtils.FORMAT_NO_MONTH_DAY; return formatDate(calendar, flags); } @@ -491,12 +508,12 @@ private String extractYearFromFormattedDate(String formattedDate, String monthAn } private void updateDisplay(boolean announce) { - if (mDayOfWeekView != null) { + if (mDayOfWeekView != null && !mPickDateWithoutDay) { mDayOfWeekView.setText(mCalendar.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.getDefault())); } - String fullDate = formatMonthDayYear(mCalendar); - String monthAndDay = formatMonthAndDay(mCalendar); + String fullDate = formatMonthDayYear(mCalendar, mPickDateWithoutDay); + String monthAndDay = formatMonthAndDay(mCalendar, mPickDateWithoutDay); String year = YEAR_FORMAT.format(mCalendar.getTime()); int yearStart = fullDate.indexOf(year); @@ -608,6 +625,21 @@ public void setYearRange(int startYear, int endYear) { } } + /** + * In some cases we don't need day, so by this method we can remove day selector form dialog and users + * can pick a date faster + * Default day is 1 + * + * @param value make it enable or disable + */ + public void setPickDateWithoutDay(boolean value) { + mPickDateWithoutDay = value; + + if (mDayPickerView != null) { + mDayPickerView.onChange(); + } + } + /** * Sets the minimal date that can be selected in this date picker. Dates before (but not including) * the specified date will be disallowed from being selected. @@ -737,6 +769,8 @@ public void onYearSelected(int year) { updatePickers(); setCurrentView(MONTH_AND_DAY_VIEW); updateDisplay(true); + if (mDayPickerView != null) + mDayPickerView.onChange(); } @Override @@ -809,6 +843,11 @@ public void tryVibrate() { mHapticFeedbackController.tryVibrate(); } + @Override + public void pickYear() { + setCurrentView(YEAR_VIEW); + } + @Override protected int contentLayout() { return R.layout.bsp_date_picker_dialog; @@ -838,6 +877,7 @@ public static class Builder extends BottomSheetPickerDialog.Builder { private int mHeaderTextColorUnselected; private int mDayOfWeekHeaderTextColorSelected; private int mDayOfWeekHeaderTextColorUnselected; + private boolean mPickDateWithoutDay = false; /** * @param listener How the parent is notified that the date is set. @@ -862,6 +902,30 @@ public Builder setFirstDayOfWeek(int startOfWeek) { return this; } + /** + * @param listener How the parent is notified that the date is set. + * @param year The initial year of the dialog. + * @param monthOfYear The initial month of the dialog. + */ + public Builder(OnDateSetListener listener, int year, int monthOfYear) { + mListener = listener; + mYear = year; + mMonthOfYear = monthOfYear; + mDayOfMonth = 1; + } + + /** + * In some cases we don't need day, so by this method we can remove day selector form dialog and users + * can pick a date faster + * Default day is 1 + * + * @param value make it enable or disable + */ + public Builder setPickDateWithoutDay(boolean value) { + mPickDateWithoutDay = value; + return this; + } + /** * Sets the range of years to be displayed by this date picker. If a {@link #setMinDate(Calendar) * minimal date} and/or {@link #setMaxDate(Calendar) maximal date} were set, dates in the @@ -980,6 +1044,7 @@ private void build(@NonNull BottomSheetPickerDialog dialog) { datePickerDialog.setDayOfWeekHeaderTextColorSelected(mDayOfWeekHeaderTextColorSelected); datePickerDialog.setDayOfWeekHeaderTextColorUnselected(mDayOfWeekHeaderTextColorUnselected); datePickerDialog.setFirstDayOfWeek(mWeekStart); + datePickerDialog.setPickDateWithoutDay(mPickDateWithoutDay); if (mMinDate != null) { datePickerDialog.setMinDate(mMinDate); } diff --git a/bottomsheetpickers/src/main/java/com/philliphsu/bottomsheetpickers/date/PagingDayPickerView.java b/bottomsheetpickers/src/main/java/com/philliphsu/bottomsheetpickers/date/PagingDayPickerView.java index c1640d1..5518097 100644 --- a/bottomsheetpickers/src/main/java/com/philliphsu/bottomsheetpickers/date/PagingDayPickerView.java +++ b/bottomsheetpickers/src/main/java/com/philliphsu/bottomsheetpickers/date/PagingDayPickerView.java @@ -96,6 +96,7 @@ class PagingDayPickerView extends LinearLayout implements OnDateChangedListener, private boolean mThemeDark; private int mAccentColor; + private boolean mPickDateWithoutDay; public PagingDayPickerView(Context context, AttributeSet attrs) { super(context, attrs); @@ -107,15 +108,16 @@ public PagingDayPickerView(Context context, DatePickerController controller) { } public PagingDayPickerView(Context context, DatePickerController controller, boolean themeDark) { - this(context, controller, themeDark, Utils.getThemeAccentColor(context)); + this(context, controller, themeDark, Utils.getThemeAccentColor(context), false); } public PagingDayPickerView(Context context, DatePickerController controller, boolean themeDark, - int accentColor) { + int accentColor, boolean mPickDateWithoutDay) { super(context); // keep these before init() mThemeDark = themeDark; mAccentColor = accentColor; + this.mPickDateWithoutDay = mPickDateWithoutDay; init(context); setController(controller); } @@ -148,6 +150,10 @@ private void init(Context context) { mTitleContainer.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { + if (mPickDateWithoutDay) { + mController.pickYear(); + return; + } int newIndex = mCurrentView == DAY_PICKER_INDEX ? MONTH_PICKER_INDEX : DAY_PICKER_INDEX; setupCurrentView(newIndex, true); } @@ -228,8 +234,8 @@ public void onChange() { void setupCurrentView(int currentView, boolean animate) { if (currentView == DAY_PICKER_INDEX || currentView == MONTH_PICKER_INDEX) { boolean isDayPicker = currentView == DAY_PICKER_INDEX; - setCurrentView(currentView, animate); - if (isDayPicker) { + setCurrentView(mPickDateWithoutDay ? MONTH_PICKER_INDEX : currentView, animate); + if (isDayPicker && !mPickDateWithoutDay) { setTitle(mAdapter.getPageTitle(mViewPager.getCurrentItem())); toggleArrowsVisibility(getPagerPosition()); } else { @@ -383,7 +389,7 @@ private void setSelectedDay(CalendarDay day) { @Override public void onDateChanged() { if (mCurrentView != DAY_PICKER_INDEX) { - setCurrentView(DAY_PICKER_INDEX, false); + setCurrentView(mPickDateWithoutDay ? MONTH_PICKER_INDEX : DAY_PICKER_INDEX, false); // Restore the title and cursors onPageSelected(mViewPager.getCurrentItem()); } @@ -529,10 +535,10 @@ public void onPageScrolled(int position, float positionOffset, int positionOffse @Override public void onPageSelected(int position) { if (mCurrentView == DAY_PICKER_INDEX) { - setTitle(mAdapter.getPageTitle(position)); - toggleArrowsVisibility(position); final int month = mAdapter.getMonth(position); final int year = mAdapter.getYear(position); + setTitle(mPickDateWithoutDay ? year + "" : mAdapter.getPageTitle(position)); + toggleArrowsVisibility(position); if (mCurrentYearDisplayed != year) { mCurrentYearDisplayed = year; } @@ -558,6 +564,9 @@ private void setTitle(CharSequence title) { * @param position The page position */ private void toggleArrowsVisibility(int position) { + if (mPickDateWithoutDay) + toggleArrowsVisibility(false, false); + else toggleArrowsVisibility(position > 0, position + 1 < mAdapter.getCount()); } @@ -568,9 +577,9 @@ private void toggleArrowsVisibility(boolean leftVisible, boolean rightVisible) { private void setArrowDrawableOnTitle(@NonNull Drawable arrow) { if (Utils.checkApiLevel(17)) { - mMonthYearTitleView.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, arrow, null); + mMonthYearTitleView.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, mPickDateWithoutDay ? null : arrow, null); } else { - mMonthYearTitleView.setCompoundDrawablesWithIntrinsicBounds(null, null, arrow, null); + mMonthYearTitleView.setCompoundDrawablesWithIntrinsicBounds(null, null, mPickDateWithoutDay ? null : arrow, null); } } @@ -589,12 +598,11 @@ private void setCurrentView(final int viewIndex, boolean animate) { } break; case MONTH_PICKER_INDEX: - if (mCurrentView != viewIndex) { - prepareMonthPickerForDisplay(mCurrentYearDisplayed); - mMonthAnimator.setDisplayedChild(MONTH_PICKER_INDEX, animate); - animateArrow(mArrowDownDrawable); - mCurrentView = viewIndex; - } + prepareMonthPickerForDisplay(mCurrentYearDisplayed); + mMonthAnimator.setDisplayedChild(MONTH_PICKER_INDEX, animate && !mPickDateWithoutDay); + refreshMonthPicker(); + animateArrow(mArrowDownDrawable); + mCurrentView = viewIndex; break; } } @@ -610,7 +618,7 @@ public void onMonthClick(MonthPickerView view, int month, int year) { // setCurrentView() is called with the 'animate' parameter set to false. // This next call would subsequently not call through, since the current // index will have already been set to DAY_PICKER_INDEX. - setCurrentView(DAY_PICKER_INDEX, true); + setCurrentView(mPickDateWithoutDay ? MONTH_PICKER_INDEX : DAY_PICKER_INDEX, true); // If the same month was selected, onPageSelected() won't automatically // call through because we're staying on the same page. // This must be called before everything else, ESPECIALLY for the diff --git a/sample/src/main/java/com/example/bottomsheetpickers/MainActivity.java b/sample/src/main/java/com/example/bottomsheetpickers/MainActivity.java index c1d5ea2..de69081 100644 --- a/sample/src/main/java/com/example/bottomsheetpickers/MainActivity.java +++ b/sample/src/main/java/com/example/bottomsheetpickers/MainActivity.java @@ -127,6 +127,7 @@ private DialogFragment createDialogWithBuilders(int checkedId) { case R.id.choice_date_picker: case R.id.choice_date_picker_dark: case R.id.choice_date_picker_custom: + case R.id.choice_date_picker_without_day: case R.id.choice_date_picker_custom_dark: { custom = checkedId == R.id.choice_date_picker_custom; customDark = checkedId == R.id.choice_date_picker_custom_dark; @@ -210,6 +211,7 @@ private DialogFragment createDialogWithSetters(int checkedId) { case R.id.choice_date_picker: case R.id.choice_date_picker_dark: case R.id.choice_date_picker_custom: + case R.id.choice_date_picker_without_day: case R.id.choice_date_picker_custom_dark: { Calendar now = Calendar.getInstance(); dialog = DatePickerDialog.newInstance( @@ -226,6 +228,7 @@ private DialogFragment createDialogWithSetters(int checkedId) { max.add(Calendar.YEAR, 10); dateDialog.setMaxDate(max); dateDialog.setYearRange(1970, 2032); + dateDialog.setPickDateWithoutDay(checkedId == R.id.choice_date_picker_without_day); if (custom || customDark) { dateDialog.setHeaderTextColorSelected(0xFFFF4081); dateDialog.setHeaderTextColorUnselected(0x4AFF4081); diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index 2d64a0e..37af70e 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -94,6 +94,12 @@ android:layout_height="48dp" android:text="Date Picker, Custom Dark"/> + +