How to use DatePickerDialog as a Preference

后端 未结 6 902
梦谈多话
梦谈多话 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 20:57

    Just a simple way to use TimePickerFragment in the settings, it doesn't really answer your question, but it can help some guys.
    Please read this before: https://developer.android.com/guide/topics/ui/settings
    From "Overview" to "Preference... attributes" of course... Oo

    controller.fragments

    public class TimePickerFragment extends DialogFragment {
    
        private TimePickerDialog.OnTimeSetListener onTimeSetListener;
        private int hours;
        private int minutes;
    
        TimePickerFragment(TimePickerDialog.OnTimeSetListener onTimeSetListener, int hours, int minutes) {
            this.onTimeSetListener = onTimeSetListener;
            this.hours = hours;
            this.minutes = minutes;
        }
    
        @NonNull
        @Override
        public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
            return new TimePickerDialog(getActivity(), R.style.dateTimePicker,
                    onTimeSetListener, hours, minutes, DateFormat.is24HourFormat(getActivity()));
        }
    }
    

    res.values.style

    <style name="dateTimePicker" parent="ThemeOverlay.MaterialComponents.Dialog">
            <item name="colorAccent">@color/colorPrimary</item>
    </style>
    

    res.xml.root_preferences.xml create the xml folder in res & the file root_preferences of course Oo

    <PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
        <PreferenceCategory app:title="Set time">
    
            <Preference
                app:key="set_time"
                app:title="Set time"
                app:summary="bla bla bla"/>
    
        </PreferenceCategory>
    </PreferenceScreen>
    

    controller.activities.SettingsActivity

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.settings_activity);
        getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.settings, new SettingsFragment())
                .commit();
    }
    

    controller.fragments.SettingsFragment

    public class SettingsFragment extends PreferenceFragmentCompat implements TimePickerDialog.OnTimeSetListener {
    
    
             private Preference setTime;
    
             public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
                setPreferencesFromResource(R.xml.root_preferences, rootKey);
                getPreference();
                configListener();
            }
    
            private void getPreference() {
                setTime = findPreference("set_time");
            }
    
            private void configListener() {
                if (setTime != null){
                    setTime.setOnPreferenceClickListener(preference -> {
                        showTimeDialog(preference);
                        return true;
                    });
                }
            }
    
            private void showTimeDialog(Preference preference) {
                String value = preference.getSharedPreferences().getString("set_time", "12:00");
                String[] time = value.split(":");
                int hours = Integer.parseInt(time[0]);
                int minutes = Integer.parseInt(time[1]);
                if (getFragmentManager() != null) {
                new TimePickerFragment(this, hours, minutes)
                    .show(getFragmentManager(), getString(R.string.tag_time_picker));
                }
            }
    
            @Override
            public void onTimeSet(TimePicker timePicker, int h, int m) {
                String time = format(Locale.getDefault(),"%02d", h) + ":" + format(Locale.getDefault(), "%02d", m);
                SharedPreferences sharedPreferences =
                        PreferenceManager.getDefaultSharedPreferences(context);
                sharedPreferences.edit().putString("set_time", time).apply();
                // if you use setOnPreferenceChangeListener on it, use setTime.callChangeListener(time);
            }
    }
    

    I didn't document anything because after reading the guide, you should all understand ^^

    0 讨论(0)
  • 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<DatePreference> {
    
            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.

    <com.example.util.timereminder.ui.prefs.custom.DatePreference
        android:title="@string/prefs_date_of_birth_title"
        android:key="@string/prefs_date_of_birth_key"
        android:defaultValue="2014-08-01"
        app:iconSpaceReserved="false"/>
    
    0 讨论(0)
  • 2021-02-18 21:02

    While looking for a TimePicker to use in preferences I found this thread. I'd like to point out that there is also a TimePicker project in that repo (link).

    The only problem is that the default.jardesc is not available, but can easily be made from the corresponding one in the DatePicker project.

    0 讨论(0)
  • 2021-02-18 21:06

    You would need to create a custom DialogPreference incorporating a DatePicker.

    0 讨论(0)
  • 2021-02-18 21:09

    Thanks to @commonsware. I followed his project and created a date picker preference dialog. So it will help someone.

    Follow the steps to open date picker in preference window.

    1 . Create a custom dialog preference for date picker.

    package com.packagename;
    
    import java.text.SimpleDateFormat;
    import java.util.Calendar;
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.preference.DialogPreference;
    import android.util.AttributeSet;
    import android.view.View;
    import android.widget.DatePicker;
    
    public class DatePreference extends DialogPreference {
        private int lastDate = 0;
        private int lastMonth = 0;
        private int lastYear = 0;
        private String dateval;
        private CharSequence mSummary;
        private DatePicker picker = null;
        public static int getYear(String dateval) {
            String[] pieces = dateval.split("-");
            return (Integer.parseInt(pieces[0]));
        }
    
        public static int getMonth(String dateval) {
            String[] pieces = dateval.split("-");
            return (Integer.parseInt(pieces[1]));
        }
    
        public static int getDate(String dateval) {
            String[] pieces = dateval.split("-");
            return (Integer.parseInt(pieces[2]));
        }
    
        public DatePreference(Context ctxt, AttributeSet attrs) {
            super(ctxt, attrs);
    
            setPositiveButtonText("Set");
            setNegativeButtonText("Cancel");
        }
    
        @Override
        protected View onCreateDialogView() {
            picker = new DatePicker(getContext());
    
            // setCalendarViewShown(false) attribute is only available from API level 11
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                picker.setCalendarViewShown(false);
            }
    
            return (picker);
        }
    
        @Override
        protected void onBindDialogView(View v) {
            super.onBindDialogView(v);
    
            picker.updateDate(lastYear, lastMonth + 1, lastDate);
        }
    
        @Override
        protected void onDialogClosed(boolean positiveResult) {
            super.onDialogClosed(positiveResult);
    
            if (positiveResult) {
                lastYear = picker.getYear();
                lastMonth = picker.getMonth();
                lastDate = picker.getDayOfMonth();
    
                String dateval = String.valueOf(lastYear) + "-"
                        + String.valueOf(lastMonth) + "-"
                        + String.valueOf(lastDate);
    
                if (callChangeListener(dateval)) {
                    persistString(dateval);
                }
            }
        }
    
        @Override
        protected Object onGetDefaultValue(TypedArray a, int index) {
            return (a.getString(index));
        }
    
        @Override
        protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
            dateval = null;
    
            if (restoreValue) {
                if (defaultValue == null) {
                    Calendar cal = Calendar.getInstance();
                    SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-dd");
                    String formatted = format1.format(cal.getTime());
                    dateval = getPersistedString(formatted);
                } else {
                    dateval = getPersistedString(defaultValue.toString());
                }
            } else {
                dateval = defaultValue.toString();
            }
            lastYear = getYear(dateval);
            lastMonth = getMonth(dateval);
            lastDate = getDate(dateval);
        }
    
        public void setText(String text) {
            final boolean wasBlocking = shouldDisableDependents();
    
            dateval = text;
    
            persistString(text);
    
            final boolean isBlocking = shouldDisableDependents();
            if (isBlocking != wasBlocking) {
                notifyDependencyChange(isBlocking);
            }
        }
    
        public String getText() {
            return dateval;
        }
    
        public CharSequence getSummary() {
            return mSummary;
        }
    
        public void setSummary(CharSequence summary) {
            if (summary == null && mSummary != null || summary != null
                    && !summary.equals(mSummary)) {
                mSummary = summary;
                notifyChanged();
            }
        }
    }
    

    2 . Add the following code in preference xml located in "res/xml/yourpreference.xml"

    <com.packagename.DatePreference 
    android:key="keyname" 
    android:title="Title of the preference" 
    android:defaultValue="2014-08-01" 
    android:summary="Summary"/>
    

    Note: Change the "keyname","Title of the preference","2014-08-01","summary" as of your requirement

    3 . If you want to change the default vaules through Preference Activity use the following code.

    package com.packagename;
    
    import android.os.Bundle;
    import com.packagename.DatePreference;
    
    public class CustomPreference extends PreferenceActivity {
      @Override
      public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        addPreferencesFromResource(R.xml.preferences);
    
        final DatePreference dp= (DatePreference) findPreference("keyname");
        dp.setText("2014-08-02");
        dp.setSummary("2014-08-02");
        dp.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
            @Override
            public boolean onPreferenceChange(Preference preference,Object newValue) {
                //your code to change values.
                dp.setSummary((String) newValue);
                return true;
            }
        });
    
      }
    }
    

    Now Enjoy...

    0 讨论(0)
  • 2021-02-18 21:14

    Here's an implementation ready to use in your project as a lib.

    To quote the source:

    Use it just like any other preference in your PreferenceScreen XML:

    <org.bostonandroid.datepreference.DatePreference
          android:key="dob" android:title="@string/dob"
          android:defaultValue="1991.01.01" />
    
    0 讨论(0)
提交回复
热议问题