How to use DatePickerDialog as a Preference

后端 未结 6 903
梦谈多话
梦谈多话 2021-02-18 20:53

I have preferences working and I am using a combination of CheckBoxPreference and EditTextPreference. I would like to replace one of them with a DatePickerDialog.

When m

6条回答
  •  轻奢々
    轻奢々 (楼主)
    2021-02-18 21:01

    In androidx DialogPreference class implementation is split into DialogPreference that handles data persistence, and PreferenceDialogFragmentCompat that handles UI. Building on top of Mahendran Sakkarai's answer, this one and on EditTextPreference class as an example, it can be done like this.

    1 . DatePreference class.

    package com.example.util.timereminder.ui.prefs.custom;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.text.TextUtils;
    import android.util.AttributeSet;
    
    import com.example.util.timereminder.R;
    
    import androidx.preference.DialogPreference;
    
    /**
     * A dialog preference that shown calendar in the dialog.
     *
     * Saves a string value.
     */
    public class DatePreference extends DialogPreference {
    
        private String mDateValue;
    
        public DatePreference(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        protected Object onGetDefaultValue(TypedArray a, int index) {
            return a.getString(index);
        }
    
        @Override
        protected void onSetInitialValue(Object defaultValue) {
            setDate(getPersistedString((String) defaultValue));
        }
    
        /**
         * Gets the date as a string from the current data storage.
         *
         * @return string representation of the date.
         */
        public String getDate() {
            return mDateValue;
        }
    
        /**
         * Saves the date as a string in the current data storage.
         *
         * @param text string representation of the date to save.
         */
        public void setDate(String text) {
            final boolean wasBlocking = shouldDisableDependents();
    
            mDateValue = text;
    
            persistString(text);
    
            final boolean isBlocking = shouldDisableDependents();
            if (isBlocking != wasBlocking) {
                notifyDependencyChange(isBlocking);
            }
    
            notifyChanged();
        }
    
        /**
         * A simple {@link androidx.preference.Preference.SummaryProvider} implementation for an
         * {@link DatePreference}. If no value has been set, the summary displayed will be 'Not
         * set', otherwise the summary displayed will be the value set for this preference.
         */
        public static final class SimpleSummaryProvider implements SummaryProvider {
    
            private static SimpleSummaryProvider sSimpleSummaryProvider;
    
            private SimpleSummaryProvider() {}
    
            /**
             * Retrieve a singleton instance of this simple
             * {@link androidx.preference.Preference.SummaryProvider} implementation.
             *
             * @return a singleton instance of this simple
             * {@link androidx.preference.Preference.SummaryProvider} implementation
             */
            public static SimpleSummaryProvider getInstance() {
                if (sSimpleSummaryProvider == null) {
                    sSimpleSummaryProvider = new SimpleSummaryProvider();
                }
                return sSimpleSummaryProvider;
            }
    
            @Override
            public CharSequence provideSummary(DatePreference preference) {
                if (TextUtils.isEmpty(preference.getDate())) {
                    return (preference.getContext().getString(R.string.not_set));
                } else {
                    return preference.getDate();
                }
            }
        }
    }
    

    2 . DatePreferenceDialogFragment class.

    package com.example.util.timereminder.ui.prefs.custom;
    
    import android.content.Context;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.DatePicker;
    
    import java.text.SimpleDateFormat;
    import java.util.Calendar;
    
    import androidx.preference.PreferenceDialogFragmentCompat;
    
    public class DatePreferenceDialogFragment extends PreferenceDialogFragmentCompat {
    
        private int mLastYear;
        private int mLastMonth;
        private int mLastDay;
        private DatePicker mDatePicker;
    
        public static DatePreferenceDialogFragment newInstance(String key) {
            final DatePreferenceDialogFragment
                    fragment = new DatePreferenceDialogFragment();
            final Bundle b = new Bundle(1);
            b.putString(ARG_KEY, key);
            fragment.setArguments(b);
            return fragment;
        }
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            String dateValue = getDatePreference().getDate();
    
            if (dateValue == null || dateValue.isEmpty()) {
                Calendar calendar = Calendar.getInstance();
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
                dateValue = df.format(calendar.getTime());
            }
    
            mLastYear = getYear(dateValue);
            mLastMonth = getMonth(dateValue);
            mLastDay = getDay(dateValue);
        }
    
        @Override
        protected View onCreateDialogView(Context context) {
            mDatePicker = new DatePicker(getContext());
            // Show spinner dialog for old APIs.
            mDatePicker.setCalendarViewShown(false);
    
            return mDatePicker;
        }
    
        @Override
        protected void onBindDialogView(View view) {
            super.onBindDialogView(view);
    
            mDatePicker.updateDate(mLastYear, mLastMonth - 1, mLastDay);
        }
    
        @Override
        public void onDialogClosed(boolean positiveResult) {
            if (positiveResult) {
                mLastYear = mDatePicker.getYear();
                mLastMonth = mDatePicker.getMonth() + 1;
                mLastDay = mDatePicker.getDayOfMonth();
    
                String dateVal = String.valueOf(mLastYear) + "-"
                        + String.valueOf(mLastMonth) + "-"
                        + String.valueOf(mLastDay);
    
                final DatePreference preference = getDatePreference();
                if (preference.callChangeListener(dateVal)) {
                    preference.setDate(dateVal);
                }
            }
        }
    
        private DatePreference getDatePreference() {
            return (DatePreference) getPreference();
        }
    
        private int getYear(String dateString) {
            String[] datePieces = dateString.split("-");
            return (Integer.parseInt(datePieces[0]));
        }
    
        private int getMonth(String dateString) {
            String[] datePieces = dateString.split("-");
            return (Integer.parseInt(datePieces[1]));
        }
    
        private int getDay(String dateString) {
            String[] datePieces = dateString.split("-");
            return (Integer.parseInt(datePieces[2]));
        }
    }
    

    3 . In PreferenceFragment.

    package com.example.util.timereminder.ui.prefs;
    
    import android.os.Bundle;
    
    import com.example.util.timereminder.R;
    import com.example.util.timereminder.ui.prefs.custom.DatePreferenceDialogFragment;
    import com.example.util.timereminder.ui.prefs.custom.DatePreference;
    
    import androidx.fragment.app.DialogFragment;
    import androidx.preference.EditTextPreference;
    import androidx.preference.Preference;
    import androidx.preference.PreferenceFragmentCompat;
    import androidx.preference.PreferenceGroup;
    
    /**
     * Displays different preferences.
     */
    public class PrefsFragment extends PreferenceFragmentCompat {
    
        @Override
        public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
            addPreferencesFromResource(R.xml.preferences);
    
            initSummary(getPreferenceScreen());
        }
    
        @Override
        public void onDisplayPreferenceDialog(Preference preference) {
            if (preference instanceof DatePreference) {
                final DialogFragment f;
                f = DatePreferenceDialogFragment.newInstance(preference.getKey());
                f.setTargetFragment(this, 0);
                f.show(getFragmentManager(), null);
            } else {
                super.onDisplayPreferenceDialog(preference);
            }
        }
    
        /**
         * Walks through all preferences.
         *
         * @param p The starting preference to search from.
         */
        private void initSummary(Preference p) {
            if (p instanceof PreferenceGroup) {
                PreferenceGroup pGrp = (PreferenceGroup) p;
                for (int i = 0; i < pGrp.getPreferenceCount(); i++) {
                    initSummary(pGrp.getPreference(i));
                }
            } else {
                setPreferenceSummary(p);
            }
        }
    
        /**
         * Sets up summary providers for the preferences.
         *
         * @param p The preference to set up summary provider.
         */
        private void setPreferenceSummary(Preference p) {
            // No need to set up preference summaries for checkbox preferences because
            // they can be set up in xml using summaryOff and summary On
            if (p instanceof DatePreference) {
                p.setSummaryProvider(DatePreference.SimpleSummaryProvider.getInstance());
            } else if (p instanceof EditTextPreference) {
                p.setSummaryProvider(EditTextPreference.SimpleSummaryProvider.getInstance());
            }
        }
    }
    

    4 . And in preference.xml. If default value left out, calendar opens on the current date.

    
    

提交回复
热议问题