honky-tonk
honky-tonk

Reputation: 73

Android date picker fragment change to spinner

I'm trying to change the date picker style to spinner for one date picker, others shall remain default.

I've tried:

public static class DatePickerFragment extends DialogFragment
            implements DatePickerDialog.OnDateSetListener {

        private int style;

        DatePickerFragment(int xml) {
            style = xml;
        }

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            final Calendar c = Calendar.getInstance();             
            final DatePickerDialog datePickerDialog = new DatePickerDialog(getActivity(), this, c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH));
            LayoutInflater inflater = requireActivity().getLayoutInflater();
            datePickerDialog.setView(inflater.inflate(style, null));
            return datePickerDialog;
        }

        @Override
        public void onDateSet(DatePicker view, int year, int month, int day) {
            Log.i("DatePicker", "received date from picker: " + day + "." + month + "." + year);
        }
    }

with style XML:

<?xml version="1.0" encoding="utf-8"?>
<DatePicker xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/datePicker"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:datePickerMode="spinner"
            android:calendarViewShown="false" />

but whenever I enter a date in the spinner and hit OK, the current (todays) date is logged in the onDateSet method and not the chosen one in the date picker.

I also tried to overwrite the OK button with:

datePickerDialog.setButton(DialogInterface.BUTTON_POSITIVE, "asd", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    Log.i("DatePicker", "received date from picker2: " + datePickerDialog.getDatePicker().getDayOfMonth() + "." + datePickerDialog.getDatePicker().getMonth()+1 + "." + datePickerDialog.getDatePicker().getYear());
                }
            });

but without change.

From my understanding and the behavior, I'm creating some overlay with inflater.inflate(style, null) where I select the date, but the overlay values are not populated.

How can I use the inflater to change the date picker style?

Note...I can't:

Thanks!

Upvotes: 4

Views: 4751

Answers (1)

Son Truong
Son Truong

Reputation: 14203

Root cause: DatePickerDialog class has a final field named mDatePicker, this field is initialized once inside the constructor, so when you call.

final DatePickerDialog datePickerDialog = new DatePickerDialog(getActivity(), this, c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH));

From that point, the mDatePicker field cannot be re-assigned to any value because its modify is final. When you call setView on the dialog, it just changes the view of the dialog without knowing the datePicker inside your custom layout.

That explains why when you change the date on the custom layout and hit OK button, it collects the value of mDatePicker to return your fragment instead of datePicker in your custom layout.

Solution 1: Using a custom style to change the date picker mode to spinner, but requires min API 21

Step 1: Define a style in styles.xml file

<style name="customDatePickerStyle" parent="Theme.AppCompat.Light.Dialog.Alert">
    <item name="android:datePickerStyle">@style/customDatePicker</item>
</style>

<style name="customDatePicker" parent="@android:style/Widget.Material.Light.DatePicker">
    <item name="android:datePickerMode">spinner</item>
    <item name="android:calendarViewShown">false</item>
</style>

Step 2: In DatePickerFragment class

public class DatePickerFragment extends DialogFragment
        implements DatePickerDialog.OnDateSetListener {

    @NonNull
    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        Calendar calendar = Calendar.getInstance();
        return new DatePickerDialog(requireActivity(),
                R.style.customDatePickerStyle,
                this,
                calendar.get(Calendar.YEAR),
                calendar.get(Calendar.MONTH),
                calendar.get(Calendar.DAY_OF_MONTH));
    }

    @Override
    public void onDateSet(DatePicker view, int year, int month, int day) {
        Log.i("DatePicker", "received date from picker: " + day + "." + month + "." + year);
    }
}

Solution 2: Create own custom date picker fragment by using a custom layout file, work for all APIs

public class DatePickerFragment extends DialogFragment
        implements DialogInterface.OnClickListener {

    private int style;
    private DatePicker mDatePicker;

    DatePickerFragment(int xml) {
        style = xml;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        View view = requireActivity().getLayoutInflater().inflate(style, null);

        Calendar calendar = Calendar.getInstance();
        mDatePicker = view.findViewById(R.id.datePicker);
        mDatePicker.init(calendar.get(Calendar.YEAR),
                calendar.get(Calendar.MONTH),
                calendar.get(Calendar.DAY_OF_MONTH),
                null);

        return new AlertDialog.Builder(requireActivity())
                .setView(view)
                .setPositiveButton(android.R.string.ok, this)
                .setNegativeButton(android.R.string.cancel, this)
                .create();
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {
        switch (which) {
            case DialogInterface.BUTTON_POSITIVE:
                mDatePicker.clearFocus();
                onDateSet(mDatePicker,
                        mDatePicker.getYear(),
                        mDatePicker.getMonth(),
                        mDatePicker.getDayOfMonth());
                break;
            case DialogInterface.BUTTON_NEGATIVE:
                dialog.dismiss();
                break;
        }
    }

    public void onDateSet(DatePicker view, int year, int month, int day) {
        Log.i("DatePicker", "received date from picker: " + day + "." + month + "." + year);
    }
}

Upvotes: 2

Related Questions