根据我们的客户需求,我们希望在所有 Android 操作系统版本的 DatePickerDialog 上保留 HOLO 样式,例如:Android 7 上的日期选择器-
From our customer demand we want to keep the HOLO style on the DatePickerDialog for all Android OS version, sth like: DatePicker on Android 7-
但它似乎无法在 Android 7 上正常工作:
But it seems to not to work correctly on Android 7:
Android 7 上的日期选择器
来自我的实现:
new DatePickerDialog(getContext(), AlertDialog.THEME_HOLO_LIGHT,
mCalendarPickerListener,
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH));
在之前的 android 7 上运行良好.有人有同样的问题吗?
It's working fine for prior android 7. Anybody has the same issue?
已发现解决方案已在 API 25 中修复https://code.google.com/u/106133255289400340786/
Edited: solution is found to be fixed in API 25 https://code.google.com/u/106133255289400340786/
我使用 DatePickerDialog 来提示用户生日.不幸的是,我在尝试使用 Material 主题对话框时收到了很多用户投诉,因此切换到它不是我的选择:我必须坚持使用 Holo 主题对话框.
I use a DatePickerDialog to prompt users for their birthdays. Unfortunately, I've received a number of complaints from users about the Material-themed dialog when trying it, so switching to it is not an option for me: I have to stick to the Holo-themed dialog.
事实证明,Android 7.0 附带了一个错误:尝试在此平台上使用 Holo 主题而不是为 DatePickerDialog 使用 broken Material 主题.请参阅以下两个错误报告:
It turns out that Android 7.0 shipped with a bug: trying to use the Holo theme on this platform instead falls back to using a broken Material theme for the DatePickerDialog. See these two bug reports:
我使用了 Jeff Lockhart 提出的这个解决方法 的修改形式,在这些错误报告中引用:
I used a modified form of this workaround by Jeff Lockhart referenced in those bug reports:
private static final class FixedHoloDatePickerDialog extends DatePickerDialog {
private FixedHoloDatePickerDialog(Context context, OnDateSetListener callBack,
int year, int monthOfYear, int dayOfMonth) {
super(context, callBack, year, monthOfYear, dayOfMonth);
// Force spinners on Android 7.0 only (SDK 24).
// Note: I'm using a naked SDK value of 24 here, because I'm
// targeting SDK 23, and Build.VERSION_CODES.N is not available yet.
// But if you target SDK >= 24, you should have it.
if (Build.VERSION.SDK_INT == 24) {
try {
final Field field = this.findField(
DatePickerDialog.class,
DatePicker.class,
"mDatePicker"
);
final DatePicker datePicker = (DatePicker) field.get(this);
final Class<?> delegateClass = Class.forName(
"android.widget.DatePicker$DatePickerDelegate"
);
final Field delegateField = this.findField(
DatePicker.class,
delegateClass,
"mDelegate"
);
final Object delegate = delegateField.get(datePicker);
final Class<?> spinnerDelegateClass = Class.forName(
"android.widget.DatePickerSpinnerDelegate"
);
if (delegate.getClass() != spinnerDelegateClass) {
delegateField.set(datePicker, null);
datePicker.removeAllViews();
final Constructor spinnerDelegateConstructor =
spinnerDelegateClass.getDeclaredConstructor(
DatePicker.class,
Context.class,
AttributeSet.class,
int.class,
int.class
);
spinnerDelegateConstructor.setAccessible(true);
final Object spinnerDelegate = spinnerDelegateConstructor.newInstance(
datePicker,
context,
null,
android.R.attr.datePickerStyle,
0
);
delegateField.set(datePicker, spinnerDelegate);
datePicker.init(year, monthOfYear, dayOfMonth, this);
datePicker.setCalendarViewShown(false);
datePicker.setSpinnersShown(true);
}
} catch (Exception e) { /* Do nothing */ }
}
}
/**
* Find Field with expectedName in objectClass. If not found, find first occurrence of
* target fieldClass in objectClass.
*/
private Field findField(Class objectClass, Class fieldClass, String expectedName) {
try {
final Field field = objectClass.getDeclaredField(expectedName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) { /* Ignore */ }
// Search for it if it wasn't found under the expectedName.
for (final Field field : objectClass.getDeclaredFields()) {
if (field.getType() == fieldClass) {
field.setAccessible(true);
return field;
}
}
return null;
}
}
这是做什么的:
DatePicker mDatePicker 字段DatePickerDelegate mDelegate 字段DatePickerSpinnerDelegate 的实例(我们想要的委托类型)DatePicker 中移除所有视图,因为它们是 Material 日历小部件DatePickerSpinnerDelegate实例,并将其分配给该对话框的mDatePicker的mDelegate字段mDatePicker 以使其为微调器充气DatePicker mDatePicker field belonging to this dialogDatePickerDelegate mDelegate field belonging to this dialogDatePickerSpinnerDelegate (the type of delegate we want)DatePicker, since they are the Material calendar widgetsDatePickerSpinnerDelegate, and assign it to the mDelegate field of mDatePicker of this dialogmDatePicker with calendar info and some params to get it to inflate the spinners为了使用这个解决方法,我在我的 Context 周围创建了一个 ContextThemeWrapper,它允许我设置一个主题,在本例中是 Holo:
To use this workaround, I create a ContextThemeWrapper around my Context, which allows me to set a theme, in this case Holo:
final Context themedContext = new ContextThemeWrapper(
this.getContext(),
android.R.style.Theme_Holo_Light_Dialog
);
final DatePickerDialog dialog = new FixedHoloDatePickerDialog(
themedContext,
datePickerListener,
calender.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH)
);
<小时>
注意事项:
try {...} catch (Exception e) {/* NOP *
解析 ISO 8601 字符串本地日期时间,就像在 UTC 中Parsing an ISO 8601 string local date-time as if in UTC(解析 ISO 8601 字符串本地日期时间,就像在 UTC 中一样)
如何将公历字符串转换为公历?How to convert Gregorian string to Gregorian Calendar?(如何将公历字符串转换为公历?)
Java:GregorianCalendar 的最大值和最小值是什么/在哪Java: What/where are the maximum and minimum values of a GregorianCalendar?(Java:GregorianCalendar 的最大值和最小值是什么/在哪里?)
1582 年 10 月 15 日之前日期的日历到日期转换.公历Calendar to Date conversion for dates before 15 Oct 1582. Gregorian to Julian calendar switch(1582 年 10 月 15 日之前日期的日历到日期转换
java日历setFirstDayOfWeek不起作用java Calendar setFirstDayOfWeek not working(java日历setFirstDayOfWeek不起作用)
Java:获取当前星期几的值Java: getting current Day of the Week value(Java:获取当前星期几的值)