Как использовать DatePickerDialog как предпочтение

У меня есть настройки, и я использую комбинацию CheckBoxPreference и EditTextPreference. Я хотел бы заменить один из них DatePickerDialog.

Когда отобразится экран настроек, если вы нажмете на одну из настроек, я бы хотел, чтобы диалоговое окно выбора даты отображалось для пользователя, чтобы выбрать дату и сохранить выбранную дату в настройках. Я видел эту работу в других приложениях, но я не вижу, как это сделать.

У меня есть диалог выбора даты, который работает с обычного вида (в соответствии с учебником), но я хотел бы использовать его с предпочтением.

Ответы

Ответ 1

Вам необходимо создать пользовательский DialogPreference, включающий DatePicker. Вот проект, показывающий пользовательский DialogPreference на основе пользовательского виджета ColorMixer.

Ответ 2

Благодаря @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. Добавьте следующий код в префикс xml, расположенный в "res/xml/yourpreference.xml"

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

Примечание. Измените "имя ключа", "Название предпочтения", "2014-08-01", "сводка" по вашему требованию

3. Если вы хотите поменять vaules по умолчанию с помощью Activity Preference, используйте следующий код.

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

  }
}

Теперь наслаждайтесь...

Ответ 3

Здесь реализация готова к использованию в вашем проекте как lib.

Чтобы указать источник:

Используйте его так же, как любые другие предпочтения в вашем XML-экране PreferenceScreen:

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

Ответ 4

В androidx реализация класса DialogPreference разделена на DialogPreference, который обрабатывает постоянство данных, и PreferenceDialogFragmentCompat, который обрабатывает пользовательский интерфейс. Основываясь на ответе Махендрана Саккарая, этого и на примере класса 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"/>

Ответ 5

При поиске TimePicker для использования в настройках я нашел этот поток. Я хотел бы указать, что в этом репо также есть проект TimePicker (ссылка).

Единственная проблема заключается в том, что default.jardesc недоступен, но может быть легко выполнен из соответствующего в проекте DatePicker.

Ответ 6

Просто простой способ использовать TimePickerFragment в настройках, он на самом деле не отвечает на ваш вопрос, но может помочь некоторым парням.
Пожалуйста, прочитайте это раньше: https://developer.android.com/guide/topics/ui/settings
Из "Обзора" в "Предпочтения... атрибуты", конечно... 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 создайте папку xml в res & файл 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);
        }
}

Я ничего не задокументировал, потому что после прочтения руководства вы все должны понять ^^