如何在Spinner模式下为Android 7.0修复DatePickerDialog? [英] How to fix DatePickerDialog in spinner mode for Android 7.0?

查看:64
本文介绍了如何在Spinner模式下为Android 7.0修复DatePickerDialog?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在开发一个简单的项目,该项目由包裹在网络视图中的网站组成,并进行少量交互,以改善网站本身与android移动设备之间的交互性。

I’m currently developing a simple project consisting of a website wrapped in a web view with minor interactions to improve interactivity between the site itself and android mobile devices.

由于该网站包含用户生日的日期输入字段,因此我一直希望实现一种与所有设备兼容的微调器格式的日期选择器。
我尝试实现以下解决方案:

Since the website includes a date input field for the user’s birthdate, I was looking to implement a datepicker in spinner format compatible with all devices. I tried implementing the following solution:

`<style name="MyAppTheme" parent="android:Theme.Material">
    <item name="android:dialogTheme">@style/MyDialogTheme</item>
    <item name="android:datePickerStyle">@style/MyDatePicker</item>
</style>
<style name="MyDialogTheme" parent="android:Theme.Material.Dialog">
    <item name="android:datePickerStyle">@style/MyDatePicker</item>
</style>
<style name="MyDatePicker" parent="android:Widget.Material.DatePicker">
    <item name="android:datePickerMode">spinner</item>
</style>`

如下所示:
在棒棒糖[spinner模式]中没有日历可视化的日期选择器对话框?

但是,正如答案所指出的,由于以下已知错误,该解决方案不适用于Android 7.0 Nougat / API 24:>://://tracktracker.google.com/issues/37119315

However, as the answer points out, this solution does not work with Android 7.0 Nougat / API 24 due to the following known bug: https://issuetracker.google.com/issues/37119315

做研究时,我遇到了一些建议的解决方案,例如:

Doing some research I came across some proposed solutions such as:

https://gist.github.com/uqmessias/d9a8dc624af935f344dfa2e8928490ec

https://gist.gi thub.com/lognaturel/232395ee1079ff9e4b1b8e7096c3afaf

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

但是在我看来,它们似乎都没有可以在装有Android 7.0的设备或任何其他设备上工作。

However in my case, none of them seem to work either for devices with Android 7.0, or any other devices.

我在android开发方面经验不足,所以我想知道是什么原因引起的,我该如何解决

I am heavily inexperienced in android development so I was wondering what could be causing this and how could I solve it, as some of the solutions have been maintained up to recently, which pretty much discards that they could have become obsolete.

我需要实现一些尚未解决的问题吗?

Do I need to implement something that hasn’t been pointed out in the code I posted and I am not aware of?

是我直接在Web视图中而不是从Web视图中调用datepicker元素的事实吗?应用本身使这些解决方案对我毫无用处?如果是这样,是否有任何解决方法?

Is it the fact that the datepicker element is being called directly from the web view and not from the app itself that renders these solutions useless to me? And if so, is there any work around for this?

推荐答案

我遇到了同样的问题(用户不想逐月滚动查看40年的时间以查找其出生年份,大多数人不知道您可以在android日期选择器中单击年份来滚动浏览年份)。像您一样,我无法让微调器普遍运行,所以我(在SO和Google的帮助下)弄清楚了如何使它开始于年份选择模式。

I ran into the same issue (users don't want to scroll back in time 40 years month by month to find their birth year and most don't know you can just click on the year in the android date picker to scroll through years). Like you, I couldn't get the spinner to work universally, so I figured out (with help from SO and Google) how to make it start in year selection mode.

我的 DatePickerDialogFragment 的代码粘贴在下面。

The code for my DatePickerDialogFragment is pasted below.

public class DatePickerDialogFragment extends DialogFragment {

    private DatePickerDialog.OnDateSetListener listener = null;

    void setListener(DatePickerDialog.OnDateSetListener listener) {
        this.listener = listener;
    }

    private static final String START_IN_YEARS = "com.myapp.picker.START_IN_YEARS";
    private static final String YEAR = "com.myapp.picker.YEAR";
    private static final String MONTH = "com.myapp.picker.MONTH";
    private static final String DAY_OF_MONTH = "com.myapp.picker.DAY_OF_MONTH";

    public static DatePickerDialogFragment newInstance(boolean startInYears, Calendar c) {
        DatePickerDialogFragment f = new DatePickerDialogFragment();

        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH);
        int day = c.get(Calendar.DAY_OF_MONTH);

        Bundle args = new Bundle();
        args.putBoolean(START_IN_YEARS, startInYears);
        args.putInt(YEAR, year);
        args.putInt(MONTH, month);
        args.putInt(DAY_OF_MONTH, day);

        f.setArguments(args);
        return f;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        Bundle args = getArguments();
        DatePickerDialog dpd = null;

        if( listener != null && args != null) {
            boolean startInYears = args.getBoolean(START_IN_YEARS);

            Context context = getActivity();
            boolean requireSpinnerMode = isBrokenSamsungDevice();
            if (requireSpinnerMode) {
                context = new ContextThemeWrapper(context, android.R.style.Theme_Holo_Light_Dialog);
            }

            int year = args.getInt(YEAR);
            int month = args.getInt(MONTH);
            int day = args.getInt(DAY_OF_MONTH);

            dpd = new DatePickerDialog(context, listener, year, month, day);

            if (startInYears && !requireSpinnerMode) {
                boolean canOpenYearView = openYearView(dpd.getDatePicker());
                if (!canOpenYearView) {
                    context = new ContextThemeWrapper(getActivity(), android.R.style.Theme_Holo_Light_Dialog);
                    dpd = new DatePickerDialog(context, listener, year, month, day);
                }
            }
        }
        else {
            setShowsDialog(false);
            dismissAllowingStateLoss();
        }

        return dpd;
    }

    private static boolean isBrokenSamsungDevice() {
        return Build.MANUFACTURER.equalsIgnoreCase("samsung") &&
                isBetweenAndroidVersions(
                        Build.VERSION_CODES.LOLLIPOP,
                        Build.VERSION_CODES.LOLLIPOP_MR1);
    }

    private static boolean isBetweenAndroidVersions(int min, int max) {
        return Build.VERSION.SDK_INT >= min && Build.VERSION.SDK_INT <= max;
    }

    private static boolean openYearView(DatePicker datePicker) {
        if( isBrokenSamsungDevice() ) {
            return false;
        }

        View v = datePicker.findViewById(Resources.getSystem().getIdentifier("date_picker_header_year", "id", "android"));
        if( v != null ) {
            v.performClick();
        }
        else {
            try {
                Field mDelegateField = datePicker.getClass().getDeclaredField("mDelegate");
                mDelegateField.setAccessible(true);
                Object delegate = mDelegateField.get(datePicker);
                Method setCurrentViewMethod = delegate.getClass().getDeclaredMethod("setCurrentView", int.class);
                setCurrentViewMethod.setAccessible(true);
                setCurrentViewMethod.invoke(delegate, 1);
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
        return true;
    }
}

Activity中的代码(成员变量和 onCreate )来启动它(并保持旋转状态)如下:

The code in the Activity (member variables and stuff in onCreate) to launch this (and preserve it on rotation) looks like this:

// Class member variables
private Calendar myCalendar = Calendar.getInstance();
private boolean birthday_is_set = false;


// this next part is in onCreate

// set the calendar date to a saved date if applicable
// and change birthday_is_set if they had saved a birthday


final DatePickerDialog.OnDateSetListener birthdayListener = new DatePickerDialog.OnDateSetListener() {

    @Override
    public void onDateSet(DatePicker view, int year, int monthOfYear,
                          int dayOfMonth) {
        // I save the date in a calendar, replace this
        // with whatever you want to do with the selected date
        myCalendar.set(Calendar.YEAR, year);
        myCalendar.set(Calendar.MONTH, monthOfYear);
        myCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
        birthday_is_set = true;
        updateBirthdayLabel();
    }
};

if (savedInstanceState != null) {
    DatePickerDialogFragment dpf;

    dpf = (DatePickerDialogFragment) getFragmentManager().findFragmentByTag("birthdayDatePicker");
    if (dpf != null) {
        // on rotation the listener will be referring to the old Activity,
        // so we have to reset it here to act on the current Activity
        dpf.setListener(birthdayListener);
    }
}

birthdayDatePicker.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // Your logic may vary here. I chose not to start it in year
        // mode if they've already selected a date.
        boolean startInYears = !birthday_is_set;
        DatePickerDialogFragment dpf = DatePickerDialogFragment.newInstance(startInYears, myCalendar);
        dpf.setListener(birthdayListener);
        dpf.show(getFragmentManager(), "birthdayDatePicker");
    }
});

这包括使它以年模式启动的黑客,以及一些随机日期的修复某个年份的三星设备上的选择器故障。这个版本已经可以使用几个月没有API 15+崩溃或用户抱怨了。

This includes both the hack to get it to start in year mode, and a fix for some random date picker failures on Samsung devices of a certain vintage. This version has been working without crashes or user complaints for API 15+ for a few months now.

编辑:更新了openYearView以在Android 10上运行

Updated openYearView to work on Android 10

这篇关于如何在Spinner模式下为Android 7.0修复DatePickerDialog?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆