How to fix DatePickerDialog in spinner mode for Android 7.0?
I ran into the same issue (users don't want to scroll back in time 40 years month by month to find their birth year and most don't know you can just click on the year in the android date picker to scroll through years). Like you, I couldn't get the spinner to work universally, so I figured out (with help from SO and Google) how to make it start in year selection mode.
The code for my DatePickerDialogFragment
is pasted below.
public class DatePickerDialogFragment extends DialogFragment {
private DatePickerDialog.OnDateSetListener listener = null;
void setListener(DatePickerDialog.OnDateSetListener listener) {
this.listener = listener;
}
private static final String START_IN_YEARS = "com.myapp.picker.START_IN_YEARS";
private static final String YEAR = "com.myapp.picker.YEAR";
private static final String MONTH = "com.myapp.picker.MONTH";
private static final String DAY_OF_MONTH = "com.myapp.picker.DAY_OF_MONTH";
public static DatePickerDialogFragment newInstance(boolean startInYears, Calendar c) {
DatePickerDialogFragment f = new DatePickerDialogFragment();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int day = c.get(Calendar.DAY_OF_MONTH);
Bundle args = new Bundle();
args.putBoolean(START_IN_YEARS, startInYears);
args.putInt(YEAR, year);
args.putInt(MONTH, month);
args.putInt(DAY_OF_MONTH, day);
f.setArguments(args);
return f;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Bundle args = getArguments();
DatePickerDialog dpd = null;
if( listener != null && args != null) {
boolean startInYears = args.getBoolean(START_IN_YEARS);
Context context = getActivity();
boolean requireSpinnerMode = isBrokenSamsungDevice();
if (requireSpinnerMode) {
context = new ContextThemeWrapper(context, android.R.style.Theme_Holo_Light_Dialog);
}
int year = args.getInt(YEAR);
int month = args.getInt(MONTH);
int day = args.getInt(DAY_OF_MONTH);
dpd = new DatePickerDialog(context, listener, year, month, day);
if (startInYears && !requireSpinnerMode) {
boolean canOpenYearView = openYearView(dpd.getDatePicker());
if (!canOpenYearView) {
context = new ContextThemeWrapper(getActivity(), android.R.style.Theme_Holo_Light_Dialog);
dpd = new DatePickerDialog(context, listener, year, month, day);
}
}
}
else {
setShowsDialog(false);
dismissAllowingStateLoss();
}
return dpd;
}
private static boolean isBrokenSamsungDevice() {
return Build.MANUFACTURER.equalsIgnoreCase("samsung") &&
isBetweenAndroidVersions(
Build.VERSION_CODES.LOLLIPOP,
Build.VERSION_CODES.LOLLIPOP_MR1);
}
private static boolean isBetweenAndroidVersions(int min, int max) {
return Build.VERSION.SDK_INT >= min && Build.VERSION.SDK_INT <= max;
}
private static boolean openYearView(DatePicker datePicker) {
if( isBrokenSamsungDevice() ) {
return false;
}
View v = datePicker.findViewById(Resources.getSystem().getIdentifier("date_picker_header_year", "id", "android"));
if( v != null ) {
v.performClick();
}
else {
try {
Field mDelegateField = datePicker.getClass().getDeclaredField("mDelegate");
mDelegateField.setAccessible(true);
Object delegate = mDelegateField.get(datePicker);
Method setCurrentViewMethod = delegate.getClass().getDeclaredMethod("setCurrentView", int.class);
setCurrentViewMethod.setAccessible(true);
setCurrentViewMethod.invoke(delegate, 1);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
return true;
}
}
The code in the Activity (member variables and stuff in onCreate
) to launch this (and preserve it on rotation) looks like this:
// Class member variables
private Calendar myCalendar = Calendar.getInstance();
private boolean birthday_is_set = false;
// this next part is in onCreate
// set the calendar date to a saved date if applicable
// and change birthday_is_set if they had saved a birthday
final DatePickerDialog.OnDateSetListener birthdayListener = new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear,
int dayOfMonth) {
// I save the date in a calendar, replace this
// with whatever you want to do with the selected date
myCalendar.set(Calendar.YEAR, year);
myCalendar.set(Calendar.MONTH, monthOfYear);
myCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
birthday_is_set = true;
updateBirthdayLabel();
}
};
if (savedInstanceState != null) {
DatePickerDialogFragment dpf;
dpf = (DatePickerDialogFragment) getFragmentManager().findFragmentByTag("birthdayDatePicker");
if (dpf != null) {
// on rotation the listener will be referring to the old Activity,
// so we have to reset it here to act on the current Activity
dpf.setListener(birthdayListener);
}
}
birthdayDatePicker.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Your logic may vary here. I chose not to start it in year
// mode if they've already selected a date.
boolean startInYears = !birthday_is_set;
DatePickerDialogFragment dpf = DatePickerDialogFragment.newInstance(startInYears, myCalendar);
dpf.setListener(birthdayListener);
dpf.show(getFragmentManager(), "birthdayDatePicker");
}
});
This includes both the hack to get it to start in year mode, and a fix for some random date picker failures on Samsung devices of a certain vintage. This version has been working without crashes or user complaints for API 15+ for a few months now.
EDIT: Updated openYearView to work on Android 10
datePickerDialog spinner instead od calendar java programatically api 24
In this API it is an error.
I found a workaround https://gist.github.com/jeffdgr8/6bc5f990bf0c13a7334ce385d482af9f
Related Topics
How to Add a Dropdown Item on the Action Bar
Android Imagebutton with a Selected State
Android Sdk Asynctask Doinbackground Not Running (Subclass)
Creating Temporary Files in Android
Android: Binding Data from a Database to a Checkbox in a Listview
Eclipse Error "Adb Server Didn't Ack, Failed to Start Daemon"
How to Programmatically Turn Off Wifi on Android Device
Calling Startactivity() from Outside of an Activity
Locationsettingsrequest Dialog to Enable Gps - Onactivityresult() Skipped
How to Avoid Soft Keyboard Pushing Up My Layout
Read Only File System on Android
React-Native: Command Not Found
How to Make a Phone Call from HTML on Android
Letting Webview on Android Work with Prefers-Color-Scheme: Dark
Error: No Resource Identifier Found for Attribute 'Adsize' in Package 'Com.Google.Example' Main.Xml