【问题标题】:How to use DatePickerDialog as a Preference如何使用 DatePickerDialog 作为首选项
【发布时间】:2010-11-18 14:56:37
【问题描述】:

我有首选项工作,我正在使用 CheckBoxPreference 和 EditTextPreference 的组合。我想用 DatePickerDialog 替换其中一个。

当我的设置屏幕显示时,如果您单击其中一个首选项,我希望弹出日期选择器对话框供用户选择日期,并将选择的日期保存在首选项中。我在其他应用程序中看到过这项工作,但我不知道如何做到这一点。

我的日期选择器对话框在常规视图中工作(根据教程),但我想根据偏好使用它。

【问题讨论】:

    标签: android


    【解决方案1】:

    感谢@commonsware。我关注了他的项目并创建了一个日期选择器首选项对话框。所以它会帮助某人。

    按照步骤在首选项窗口中打开日期选择器。

    1 .为日期选择器创建自定义对话框首选项。

    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 。在“res/xml/yourpreference.xml”中的偏好xml中添加以下代码

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

    注意:根据您的要求更改“keyname”、“Title of the preference”、“2014-08-01”、“summary”

    3 .如果您想通过 Preference Activity 更改默认值,请使用以下代码。

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

    现在享受...

    【讨论】:

    • 嗨,你为什么要在 onDialogClosed 本地创建另一个 dateval?
    • 有一个小bug应该是+1的一个月
    • 这很好。但是在所有带有日期和时间的示例中,我看到人们对日期格式进行硬编码。在许多国家/地区,日期格式不同。您应该使用设备的本地日期格式!
    • 正如@user1209216 指出的那样,行picker.updateDate(lastYear, lastMonth, lastDate);应该是 picker.updateDate(lastYear, lastMonth-1, lastDate);
    • 谢谢!就一个问题。如何设置 datePickerDialog 的样式?
    【解决方案2】:

    只是在设置中使用 TimePickerFragment 的一种简单方法,它并不能真正回答您的问题,但它可以帮助一些人。
    请在此之前阅读:https://developer.android.com/guide/topics/ui/settings
    从“Overview”到“Preference...attributes”当然... 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 在 res 中创建 xml 文件夹,当然还有文件 root_preferences 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);
            }
    }
    

    我没有记录任何东西,因为看完指南,你们应该都明白了^^

    【讨论】:

      【解决方案3】:

      在 androidx 中,DialogPreference 类实现分为处理数据持久性的 DialogPreference 和处理 UI 的 PreferenceDialogFragmentCompat。以Mahendran Sakkarai's answerthis one 和EditTextPreference 类为例,可以这样做。

      1 . DatePreference 类。

      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 类。

      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 .在 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 。在preference.xml 中。如果省略默认值,日历会在当前日期打开。

      <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"/>
      

      【讨论】:

      • 感谢您的回答。请注意,稳定版“androidx.preference:preference:1.0.0”不包含SummaryProvider。我正在使用“androidx.preference:preference-ktx:1.1.0-beta01”来解决这个问题。
      【解决方案4】:

      您需要创建一个自定义 DialogPreference 并包含一个 DatePicker

      【讨论】:

      • 这对我很有帮助,谢谢。我创建了一个自定义类,但现在如何将它添加到我现有的偏好中?我现有的偏好是在 XML 中定义的。如何添加它并使其成为我十个偏好中的第三个?
      • @MLW:只需将其添加为元素即可。您需要完全限定类名(例如,&lt;com.commonsware.my.custom.Preference&gt;)。
      • 谢谢@commonsware!就一个问题。如何设置 datePickerDialog 的样式?
      • @CommonsWare,链接已失效
      【解决方案5】:

      Here 是一个可以在您的项目中作为库使用的实现。

      引用来源:

      像使用 PreferenceScreen XML 中的任何其他首选项一样使用它:

      <org.bostonandroid.datepreference.DatePreference
            android:key="dob" android:title="@string/dob"
            android:defaultValue="1991.01.01" />
      

      【讨论】:

      • 这是最好的。这个类应该有一个变化,那就是public static DateFormat summaryFormatter() 应该返回SimpleDateFormat.getDateInstance(DateFormat.LONG); 以使用用户本地日期格式。
      【解决方案6】:

      在寻找用于偏好设置的 TimePicker 时,我发现了这个线程。 我想指出,该 repo (link) 中还有一个 TimePicker 项目。

      唯一的问题是 default.jardesc 不可用,但可以很容易地从 DatePicker 项目中的相应文件中制作。

      【讨论】:

        【解决方案7】:

        我将展示我的代码以从 SettingsActivity.java 中选择并保存日期,该日期应用于 Preferences 片段类。适用于从 API 级别 16 到 API 级别 29 的所有设备。

        首先,将此标签放在“root_preferences.xml”文件中的&lt;PreferenceScreen&gt;&lt;PreferenceCategory&gt; 标签之间(如果有的话):

            <Preference
                app:key="date_pref"
                app:title="Set date"
                app:useSimpleSummaryProvider="true" />
        

        最后,将此代码放入 SettingsActivity.java 文件中,在名为 SettingsFragment 的子类中:

        public static class SettingsFragment extends PreferenceFragmentCompat {
            SharedPreferences settings;
        
            @Override
            public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
                settings = requireContext().getSharedPreferences(requireContext().getPackageName() + "_preferences", Context.MODE_PRIVATE);
                setPreferencesFromResource(R.xml.root_preferences, rootKey);
                    
                Preference date_pref = getPreferenceManager().findPreference("date_pref");
                assert date_pref != null;
                date_pref.setSummary(settings.getString("date_pref", ""));
                date_pref.setOnPreferenceClickListener(datePicker);
            }
            
            Preference.OnPreferenceClickListener datePicker = new Preference.OnPreferenceClickListener() {
                @Override
                public boolean onPreferenceClick(Preference preference) {
                    Calendar cal = Calendar.getInstance();
                    int cal_month = cal.get(Calendar.MONTH);
                    int cal_day = cal.get(Calendar.DAY_OF_MONTH);
                    int cal_year = cal.get(Calendar.YEAR);
                    DatePickerDialog datePickerDialog = new DatePickerDialog(requireActivity(), new DatePickerDialog.OnDateSetListener() {
                        @Override
                        public void onDateSet(DatePicker view, int year, int month, int day) {
                            String datePicked = day + "." + month + "." + year;
                            settings.edit().putString("date_pref", datePicked).apply();
                            preference.setSummary(datePicked);
                        }
                    }, cal_year, cal_month, cal_day);
                    datePickerDialog.show();
                    return false;
                }
            };
        }
        

        不要忘记这个导入:

        import android.app.DatePickerDialog;
        import android.content.Context;
        import android.content.SharedPreferences;
        import java.util.Calendar;
        

        别忘了Vote Up我的帖子:)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-08-17
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多