Cómo corregir DatePickerDialog en modo spinner para Android 7.0?

Oranakia:

Actualmente estoy desarrollando un proyecto simple que consiste en una página web envuelto en una vista web con las interacciones menores para mejorar la interactividad entre el sitio en sí y dispositivos móviles Android.

Desde el sitio web incluye un campo de entrada de fecha para la fecha de nacimiento del usuario, que estaba buscando implementar un selector de fechas en formato spinner compatible con todos los dispositivos. Probé la aplicación de la siguiente solución:

`<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>`

Como se muestra en: diálogo selector de fechas sin visualización de calendario en [Modo spinner] piruleta?

Sin embargo, como la respuesta señala, esta solución no funciona con Android 7.0 Turrón / API 24 debido al siguiente error conocido: https://issuetracker.google.com/issues/37119315

Haciendo un poco de investigación me encontré con algunas soluciones propuestas tales como:

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

https://gist.github.com/lognaturel/232395ee1079ff9e4b1b8e7096c3afaf

DatePickerDialog Holo no Styling en Android 7 Turrón

Sin embargo, en mi caso, ninguno de ellos parece funcionar bien para los dispositivos con Android 7.0, o cualquier otro dispositivo.

Estoy muy poca experiencia en el desarrollo de Android así que me preguntaba qué podría estar causando esto y cómo podría resolverlo, ya que algunas de las soluciones se han mantenido hasta hace poco, que prácticamente descartes que podrían haber quedado obsoletos.

¿Es necesario poner en práctica algo que no se ha señalado en el código que he publicado y no soy consciente de?

Es el hecho de que el elemento selector de fechas está siendo llamada directamente desde la vista web y no de la propia aplicación que hace que estas soluciones inútiles para mí? Y si es así, ¿Hay alguna solución para esto?

Tyler V:

Me encontré con el mismo problema (los usuarios no quieren desplazarse hacia atrás en el tiempo 40 años mes a mes a encontrar su año de nacimiento y la mayoría no sabe que acaba de hacer clic en el año en el selector de fechas androide para desplazarse por año) . Al igual que usted, no pude conseguir el control de giro a la obra universal, por lo que me di cuenta (con la ayuda de SO y Google) cómo hacer que se inicia en el modo de selección de este año.

El código para mi DatePickerDialogFragmentse pega a continuación.

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

El código de la Actividad (variables miembro y cosas en onCreate) para poner en marcha este (y preservarlo en rotación) se ve así:

// 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");
    }
});

Esto incluye tanto el truco para conseguir que se inicia en el modo de ejercicio, y una solución para algunos fracasos selector de fechas al azar en los dispositivos de Samsung de una determinada época. Esta versión ha estado trabajando sin accidentes o quejas de los usuarios de la API 15+ durante unos meses.

EDIT: Actualización openYearView a trabajar en Android 10

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=219420&siteId=1
Recomendado
Clasificación