解决 DatePickerDialog 在 Android7.0 API24 上使用 AlertDialog.THEME_TRADITIONAL、AlertDialog.THEME_HOLO_DARK

DatePickerDemoForAndroid24

解决 DatePickerDialog 在 Android7.0 API24 上使用AlertDialog.THEME_TRADITIONALAlertDialog.THEME_HOLO_DARKAlertDialog.THEME_HOLO_LIGHT等样式时无法显示为 Spinner 样式的问题。


完整项目与演示地址

Github

API24 无法显示 Spinner 样式

在设备 API24 时,调用DatePickerDialog来选择日期和时间时,如果指定的主题为THEME_TRADITIONALTHEME_HOLO_DARKTHEME_HOLO_LIGHT,会出现和其他 API Level 不一样的对话框。

  • THEME_TRADITIONAL
    解决 DatePickerDialog 在 Android7.0 API24 上使用 AlertDialog.THEME_TRADITIONAL、AlertDialog.THEME_HOLO_DARK

  • THEME_HOLO_DARK
    解决 DatePickerDialog 在 Android7.0 API24 上使用 AlertDialog.THEME_TRADITIONAL、AlertDialog.THEME_HOLO_DARK

  • THEME_HOLO_LIGHT
    解决 DatePickerDialog 在 Android7.0 API24 上使用 AlertDialog.THEME_TRADITIONAL、AlertDialog.THEME_HOLO_DARK

解决方式

Build.VERSION.SDK_INT == 24时做特殊处理,传入对应 theme 的 ContextThemeWrapper,使用 DatePickerDialogForAndroid24 来展示 Spinner 样式的 DatePickerDialog。

    /**
     * Api24下显示Spinner样式的Dialog
     * @param theme ContextThemeWrapper的theme与DialogTheme的对应关系如下
     *              android.R.style.Theme_Dialog -> AlertDialog.THEME_TRADITIONAL
     *              android.R.style.Theme_Holo -> AlertDialog.THEME_HOLO_DARK
     *              android.R.style.Theme_Holo_Light -> AlertDialog.THEME_HOLO_LIGHT
     */
    private fun showDatePickerDialogApi24(theme: Int) {
        val themeContext =
            ContextThemeWrapper(this@MainActivity, theme)
        try {
            val dialog = DatePickerDialogForAndroid24(
                themeContext,
                null,
                Calendar.getInstance().get(Calendar.YEAR),
                Calendar.getInstance().get(Calendar.MONTH),
                Calendar.getInstance().get(Calendar.DAY_OF_MONTH)
            )
            dialog.create()
            dialog.getButton(DialogInterface.BUTTON_NEGATIVE).visibility = View.GONE
            dialog.show()
        } catch (e: Exception) {
            showAlertDialog(e.toString())
            e.printStackTrace()
        }
    }
class DatePickerDialogForAndroid24(
    context: Context,
    listener: OnDateSetListener?,
    year: Int,
    monthOfYear: Int,
    dayOfMonth: Int
) : DatePickerDialog(context, listener, year, monthOfYear, dayOfMonth) {

    init {
        if (Build.VERSION.SDK_INT == 24) {
            try {
                val field = findField(
                    DatePickerDialog::class.java,
                    DatePicker::class.java,
                    "mDatePicker"
                )
                val datePicker = field.get(this) as DatePicker
                val delegateClass =
                    Class.forName("android.widget.DatePicker\$DatePickerDelegate")
                val delegateField = findField(DatePicker::class.java, delegateClass, "mDelegate")

                val delegate = delegateField.get(datePicker)
                val spinnerDelegateClass = Class.forName("android.widget.DatePickerSpinnerDelegate")

                if (delegate.javaClass != spinnerDelegateClass) {
                    delegateField.set(datePicker, null)
                    datePicker.removeAllViews()

                    val spinnerDelegateConstructor = spinnerDelegateClass.getDeclaredConstructor(
                        DatePicker::class.java,
                        Context::class.java,
                        AttributeSet::class.java,
                        Int::class.java,
                        Int::class.java
                    )
                    spinnerDelegateConstructor.isAccessible = true
                    val spinnerDelegate = spinnerDelegateConstructor.newInstance(
                        datePicker,
                        context,
                        null,
                        android.R.attr.datePickerStyle,
                        0
                    )
                    delegateField.set(datePicker, spinnerDelegate)

                    datePicker.init(year, monthOfYear, dayOfMonth, this)
                    datePicker.calendarViewShown = false
                    datePicker.spinnersShown = true
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
        else{
            throw Exception("Not Android 7.0 Device")
        }
    }
}

完整演示

  • API24
    解决 DatePickerDialog 在 Android7.0 API24 上使用 AlertDialog.THEME_TRADITIONAL、AlertDialog.THEME_HOLO_DARK
  • API30
    解决 DatePickerDialog 在 Android7.0 API24 上使用 AlertDialog.THEME_TRADITIONAL、AlertDialog.THEME_HOLO_DARK
上一篇:跟我学Android之十 对话框


下一篇:Android -AlertDialog 对话框