Android DatePickerDialog android.R.style.Theme_Holo_Light_Dialog_NoActionBar 在7.0手机上不工作问题

在不同语言环境中,日历的格式是不同的,比如在英语环境中,格式为:MM-dd-YY,而且月份显示的是英文并非数字;中文环境中是YY-MM-dd。如果想要改变可以设置setDisplayedValues()改变英文月份到数字,通过mSpinners.addView()NumberPicker )改变顺序。

String months[] = {"1", "2", "3", "4", "5", "6",
                "7", "8", "9", "10", "11", "12"};

        FixedHoloDatePickerDialog dlg = new FixedHoloDatePickerDialog(new ContextThemeWrapper(this,android.R.style.Theme_Holo_Light_Dialog_NoActionBar), (view, year, month, dayOfMonth) -> {
                    yearTv.setText(year + "");
                    monthTv.setText((month + 1) + "");
                    dayTv.setText(dayOfMonth + "");
                    yy = year;
                    mm = month;
                    dd = dayOfMonth;
                }, yy, mm, dd) {
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                LinearLayout mSpinners = findViewById(getContext().getResources().getIdentifier("android:id/pickers", null, null));
                if (mSpinners != null) {
                    NumberPicker mMonthSpinner = findViewById(getResources().getIdentifier("android:id/month", null, null));
                    NumberPicker mDaySpinner = findViewById(getResources().getIdentifier("android:id/day", null, null));
                    NumberPicker mYearSpinner = findViewById(getResources().getIdentifier("android:id/year", null, null));
                    mSpinners.removeAllViews();
                    if (mYearSpinner != null) {
                        mSpinners.addView(mYearSpinner);
                    }
                    if (mMonthSpinner != null) {
                        mMonthSpinner.setDisplayedValues(months);
                        mSpinners.addView(mMonthSpinner);
                    }
                    if (mDaySpinner != null) {
                        mSpinners.addView(mDaySpinner);
                    }
                }
            }

            @Override
            public void onDateChanged(DatePicker view, int year, int month, int day) {
                super.onDateChanged(view, year, month, day);
                NumberPicker mMonthSpinner = findViewById(getResources().getIdentifier("android:id/month", null, null));
                if (mMonthSpinner != null) {
                    mMonthSpinner.setDisplayedValues(months);
                }
            }
        };

        dlg.getDatePicker().setCalendarViewShown(false);
        dlg.getDatePicker().setSpinnersShown(true);
        dlg.getDatePicker().setMaxDate(System.currentTimeMillis());
        dlg.show();

FixedHoloDatePickerDialog 这使用反射来访问私有字段。一般来说,这不是一个强大的方法,你不能指望它。我在这里减轻风险1)将此限制为单个SDK版本,v24; 2)将整个反射代码包裹在一个try {...} catch (Exception e) {/* NOP */}块中,因此如果任何反射失败,则不会发生任何事情,并且将使用(可悲地破坏)默认材料回退。

public class FixedHoloDatePickerDialog extends DatePickerDialog {
    public 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 通过
android:calendarViewShown="false"
android:spinnersShown="true"
android:datePickerMode="spinner"
也可以做到轻便主题,但是如果想要修改顺序以及英文环境下格式化日期。那么7.0手机就是个坑,因为下面这句话转化英文月份为数字,会报数组越界异常:

String months[] = {"1", "2", "3", "4", "5", "6",
                "7", "8", "9", "10", "11", "12"};
...
((NumberPicker) ((ViewGroup) ((ViewGroup) datePicker.getChildAt(0)).getChildAt(0)).getChildAt(0)).setDisplayedValues(months);

你可能感兴趣的:(Android DatePickerDialog android.R.style.Theme_Holo_Light_Dialog_NoActionBar 在7.0手机上不工作问题)