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
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 ^^
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"/>
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.
You would need to create a custom DialogPreference
incorporating a DatePicker
.
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...
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" />