Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Android 7牛轧糖上的DatePickerDialog Holo样式设置失败_Java_Android_Calendar - Fatal编程技术网

Java Android 7牛轧糖上的DatePickerDialog Holo样式设置失败

Java Android 7牛轧糖上的DatePickerDialog Holo样式设置失败,java,android,calendar,Java,Android,Calendar,根据我们的客户需求,我们希望在所有Android OS版本的DatePickerDialog上保持HOLO风格,例如: 但在Android 7上似乎无法正常工作: 来自我的实现: new DatePickerDialog(getContext(), AlertDialog.THEME_HOLO_LIGHT, mCalendarPickerListener, calendar.get(Calenda

根据我们的客户需求,我们希望在所有Android OS版本的DatePickerDialog上保持HOLO风格,例如:

但在Android 7上似乎无法正常工作:

来自我的实现:

new DatePickerDialog(getContext(), AlertDialog.THEME_HOLO_LIGHT,
                        mCalendarPickerListener,
                        calendar.get(Calendar.YEAR),
                        calendar.get(Calendar.MONTH),
                        calendar.get(Calendar.DAY_OF_MONTH));
它在之前的安卓7上运行良好。有人有同样的问题吗

已编辑:在API 25中发现解决方案是固定的
日期选择器有自己的独立样式


我认为您需要
R.style.Widget.Holo.DatePicker
而不是
AlertDialog.THEME\u Holo\u LIGHT
。您可能需要创建自己的空样式,将
@android:style/Widget.Holo.DatePicker
作为其父样式并使用它

我使用
DatePickerDialog
提示用户生日。不幸的是,我在尝试使用材料主题对话框时收到了很多用户的投诉,因此切换到材料主题对话框对我来说不是一个选择:我必须坚持使用全息主题对话框

结果证明,Android 7.0附带了一个bug:尝试在这个平台上使用Holo主题,而不是在
DatePickerDialog
中使用中断的材质主题。请参阅以下两个错误报告:

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;
    }
}
我在这些bug报告中使用了一种经过修改的引用形式:

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

注释

  • 这使用反射来访问私有字段。一般来说,这不是一个健壮的方法,您不能指望它。我在这里通过1)将此限制为单个SDK版本v24来降低风险;和2)将反射代码的整个位包装在
    try{…}catch(异常e){/*NOP*/}
    块中,因此如果任何反射失败,将不会发生任何事情,并且将使用(令人遗憾地损坏的)默认材质回退
  • 上面的bug报告声称这个问题已经在Android 7.1(SDK 25)中修复。我还没有测试过这个
  • 用于
    TimePickerDialog
    的是遇到类似问题的。我将其修改为使用
    DatePickerDialog
    ,并简化了解决方案,使其不那么通用,更适合我的具体用例。但是,您可以使用更完整的原始版本,只需将其调整为
    Date
    ,而不是
    Time

试着遵循它的工作原理。我已经测试过了。而且它没有空白

另外,
mDatePickerListener
是您可以创建的我的datepickerlistener

//Setting theme to android.R.style.Theme_Holo_Light_Dialog  
Calendar cal = Calendar.getInstance(TimeZone.getDefault());
DatePickerDialog datePicker = new DatePickerDialog(getContext(), android.R.style.Theme_Holo_Light_Dialog,
                    mDatePickerListener,
                    cal.get(Calendar.YEAR),
                    cal.get(Calendar.MONTH),
                    cal.get(Calendar.DAY_OF_MONTH));

datePicker.setCancelable(false);
datePicker.setTitle(getString(R.string.select_your_dob));
//This line is important to remove blank gaps
datePicker.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
datePicker.show();
除此之外:自API 28起,全息灯主题已被弃用。如果您的目标是API 21/Lollipop设备和更新版本,则应使用材质设计样式,请选中。我定义了这些样式,然后链接到
ContextThemeWrapper
中的
R.style.dlg\u日期选择器

<style name="dlg_datePicker" parent="Theme.AppCompat.Light.Dialog">
    <item name="android:datePickerStyle">@style/datePicker_style</item>
    <item name="android:textSize">18sp</item>
</style>

<style name="datePicker_style" parent="android:Widget.Material.Light.DatePicker">
    <item name="android:datePickerMode">spinner</item>
</style>

@样式/日期选择器\u样式
18便士
纺纱机

你更新了你的支持库吗?@Shuddh已经尝试过了,但还是一样:)我尝试了“24.2.1”,我也遇到了这个问题。有人有解决办法吗?我的解决办法是推回土生土长的拾荒者风格。不再强制HOLO_LIGHT…它不能正常工作,而是显示一个带有空白空白的全屏日历。尽管这是一个解决问题,但无论如何,谢谢,这听起来是可行的。听起来正确的修复应该使用API 25 set date listener不起作用,总是返回您保存的初始日期=)谢谢,它起作用了!但是文本和线条的颜色是白色的,我怎么能改变它呢?这在HTC One M或三星Galaxy A5-2016上不起作用,因为Android 7/API 24:它让日期选择器处于日历模式,而不是旋转模式。