在Android 7牛轧糖上,DatePickerDialog Holo样式失败

根据我们的客户需求,我们希望在所有Android操作系统版本上保持DatePickerDialog的HOLO风格,例如: DatePicker on Android 7-

但它似乎不能在Android 7上正常工作:

Android 7上的DatePicker

从我的实现:

new DatePickerDialog(getContext(), AlertDialog.THEME_HOLO_LIGHT, mCalendarPickerListener, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)); 

对于之前的android 7来说它工作的很好。任何人都有同样的问题?

编辑:解决scheme被发现在API 25中修复https://code.google.com/u/106133255289400340786/

Solutions Collecting From Web of "在Android 7牛轧糖上,DatePickerDialog Holo样式失败"

我使用DatePickerDialog来提示用户的生日。 不幸的是,在尝试使用时,我收到了很多来自用户的关于材质主题对话的投诉,所以切换到这个对话框不是我的select:我必须坚持以全息为主题的对话框。

事实certificate,Android 7.0提供了一个错误:试图在这个平台上使用Holo主题,而不是使用DatePickerDialog一个破碎的材料主题。 看到这两个错误报告:

  • 问题222808
  • Issue 222208

我在这些错误报告中引用了Jeff Lockhart的这个解决方法的修改forms:

 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的实例(我们需要的委托types)
  • DatePicker删除所有视图,因为它们是Material日历小部件
  • 创build一个DatePickerSpinnerDelegate的新实例,并将其分配给该对话框的mDatePickermDelegate字段
  • 用日历信息和一些参数重新初始化mDatePicker ,以使其mDatePicker旋转器

要使用这种解决方法,我创build了一个ContextThemeWrapper围绕我的Context ,它允许我设置一个主题,在这种情况下,全息:

 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) ); 

备注

  • 这使用reflection访问私人领域。 一般来说,这不是一个可靠的方法,你不能指望它。 我正在通过以下方式来降低风险:1)将其限制为单个SDK版本v24; 2)在try {...} catch (Exception e) {/* NOP */}块中包装整个reflection代码,所以如果任何reflection失败,什么都不会发生,并且(可悲的是破坏)默认材料回退将被使用。
  • 上面的错误报告声称这个问题已经在Android 7.1(SDK 25)中解决了。 我没有testing过这个。
  • 原来的解决方法代码是TimePickerDialog遇到类似的问题。 我已经修改它与DatePickerDialog使用,而且简化了解决scheme,使其不那么通用,更具体到我的确切用例。 但是,您可以使用更完整的原始版本,只需调整Date而不是Time

dateselect器有它自己的独立样式https://developer.android.com/reference/android/R.style.html#Widget_DatePicker

我想你需要R.style.Widget.Holo.DatePicker而不是AlertDialog.THEME_HOLO_LIGHT 。 有可能你可能需要创build自己的具有@android:style/Widget.Holo.DatePicker的空样式,因为它是父类,并使用它。