TimePicker в окне предпочтений
Я хотел бы создать поле предпочтений под названием Interval
, и я хочу, чтобы вы могли всплывать TimePicker
и устанавливать mm:ss
с установленным значением с минимальным значением 00:30
и шагом 30 секунд.
Можно ли использовать TimePicker
в PreferenceScreen
?
Ответы
Ответ 1
В Android нет встроенного TimePreference. Однако создать собственное достаточно просто. Здесь я сделал:
import android.content.Context;
import android.content.res.TypedArray;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TimePicker;
public class TimePreference extends DialogPreference {
private int lastHour=0;
private int lastMinute=0;
private TimePicker picker=null;
public static int getHour(String time) {
String[] pieces=time.split(":");
return(Integer.parseInt(pieces[0]));
}
public static int getMinute(String time) {
String[] pieces=time.split(":");
return(Integer.parseInt(pieces[1]));
}
public TimePreference(Context ctxt, AttributeSet attrs) {
super(ctxt, attrs);
setPositiveButtonText("Set");
setNegativeButtonText("Cancel");
}
@Override
protected View onCreateDialogView() {
picker=new TimePicker(getContext());
return(picker);
}
@Override
protected void onBindDialogView(View v) {
super.onBindDialogView(v);
picker.setCurrentHour(lastHour);
picker.setCurrentMinute(lastMinute);
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
lastHour=picker.getCurrentHour();
lastMinute=picker.getCurrentMinute();
String time=String.valueOf(lastHour)+":"+String.valueOf(lastMinute);
if (callChangeListener(time)) {
persistString(time);
}
}
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return(a.getString(index));
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
String time=null;
if (restoreValue) {
if (defaultValue==null) {
time=getPersistedString("00:00");
}
else {
time=getPersistedString(defaultValue.toString());
}
}
else {
time=defaultValue.toString();
}
lastHour=getHour(time);
lastMinute=getMinute(time);
}
}
Ответ 2
Я изменил код из первого ответа:
- хранит выбранное время в длинной форме (миллисекунды), с которой легче работать (используя Календарь), а затем строка
- он автоматически отображает выбранное время в сводном поле в пользовательском формате (12 или 24 часа).
Обновленный код:
public class TimePreference extends DialogPreference {
private Calendar calendar;
private TimePicker picker = null;
public TimePreference(Context ctxt) {
this(ctxt, null);
}
public TimePreference(Context ctxt, AttributeSet attrs) {
this(ctxt, attrs, android.R.attr.dialogPreferenceStyle);
}
public TimePreference(Context ctxt, AttributeSet attrs, int defStyle) {
super(ctxt, attrs, defStyle);
setPositiveButtonText(R.string.set);
setNegativeButtonText(R.string.cancel);
calendar = new GregorianCalendar();
}
@Override
protected View onCreateDialogView() {
picker = new TimePicker(getContext());
return (picker);
}
@Override
protected void onBindDialogView(View v) {
super.onBindDialogView(v);
picker.setCurrentHour(calendar.get(Calendar.HOUR_OF_DAY));
picker.setCurrentMinute(calendar.get(Calendar.MINUTE));
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
calendar.set(Calendar.HOUR_OF_DAY, picker.getCurrentHour());
calendar.set(Calendar.MINUTE, picker.getCurrentMinute());
setSummary(getSummary());
if (callChangeListener(calendar.getTimeInMillis())) {
persistLong(calendar.getTimeInMillis());
notifyChanged();
}
}
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return (a.getString(index));
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
if (restoreValue) {
if (defaultValue == null) {
calendar.setTimeInMillis(getPersistedLong(System.currentTimeMillis()));
} else {
calendar.setTimeInMillis(Long.parseLong(getPersistedString((String) defaultValue)));
}
} else {
if (defaultValue == null) {
calendar.setTimeInMillis(System.currentTimeMillis());
} else {
calendar.setTimeInMillis(Long.parseLong((String) defaultValue));
}
}
setSummary(getSummary());
}
@Override
public CharSequence getSummary() {
if (calendar == null) {
return null;
}
return DateFormat.getTimeFormat(getContext()).format(new Date(calendar.getTimeInMillis()));
}
}
Ответ 3
Для тех, кому реализация пользовательского Preference не так очевидна (например, это было не для меня), вы должны добавить это к своему preferences.xml
или тому, что вы его вызываете.
В итоге вы получите что-то вроде этого:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<EditTextPreference
android:key="editTextPref_Key"
android:title="@string/editTextPref_title"/>
<com.example.myapp.TimePreference
android:key="timePrefA_Key"
android:title="@string/timePrefA_title"/>
<com.example.myapp.TimePreference
android:key="timePrefB_Key"
android:title="@string/timePrefB_title"/>
</PreferenceScreen>
Предполагая, что вы добавили TimePreference в свой собственный корневой пакет:
(src/com/example/myapp/TimePreference.java
)
Ответ 4
Для Preferences Support Library
необходим другой код. Для этого требуется два пользовательских класса TimePreference
и TimePreferenceDialogFragmentCompat
, а также метод onDisplayPreferenceDialog
в классе расширения PreferenceFragmentCompat
.
TimePreference.java
package com.test;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.v7.preference.DialogPreference;
import android.util.AttributeSet;
public class TimePreference extends DialogPreference
{
public int hour = 0;
public int minute = 0;
public static int parseHour(String value)
{
try
{
String[] time = value.split(":");
return (Integer.parseInt(time[0]));
}
catch (Exception e)
{
return 0;
}
}
public static int parseMinute(String value)
{
try
{
String[] time = value.split(":");
return (Integer.parseInt(time[1]));
}
catch (Exception e)
{
return 0;
}
}
public static String timeToString(int h, int m)
{
return String.format("%02d", h) + ":" + String.format("%02d", m);
}
public TimePreference(Context context, AttributeSet attrs)
{
super(context, attrs);
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index)
{
return a.getString(index);
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue)
{
String value;
if (restoreValue)
{
if (defaultValue == null) value = getPersistedString("00:00");
else value = getPersistedString(defaultValue.toString());
}
else
{
value = defaultValue.toString();
}
hour = parseHour(value);
minute = parseMinute(value);
}
public void persistStringValue(String value)
{
persistString(value);
}
}
TimePreferenceDialogFragmentCompat.java
package com.test;
import android.content.Context;
import android.support.v7.preference.DialogPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceDialogFragmentCompat;
import android.view.View;
import android.widget.TimePicker;
public class TimePreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat implements DialogPreference.TargetFragment
{
TimePicker timePicker = null;
@Override
protected View onCreateDialogView(Context context)
{
timePicker = new TimePicker(context);
return (timePicker);
}
@Override
protected void onBindDialogView(View v)
{
super.onBindDialogView(v);
timePicker.setIs24HourView(true);
TimePreference pref = (TimePreference) getPreference();
timePicker.setCurrentHour(pref.hour);
timePicker.setCurrentMinute(pref.minute);
}
@Override
public void onDialogClosed(boolean positiveResult)
{
if (positiveResult)
{
TimePreference pref = (TimePreference) getPreference();
pref.hour = timePicker.getCurrentHour();
pref.minute = timePicker.getCurrentMinute();
String value = TimePreference.timeToString(pref.hour, pref.minute);
if (pref.callChangeListener(value)) pref.persistStringValue(value);
}
}
@Override
public Preference findPreference(CharSequence charSequence)
{
return getPreference();
}
}
Необходимые изменения в классе PreferenceFragmentCompat
расширения
public static class PreferencesFragment extends PreferenceFragmentCompat
{
....
@Override
public void onDisplayPreferenceDialog(Preference preference)
{
DialogFragment dialogFragment = null;
if (preference instanceof TimePreference)
{
dialogFragment = new TimePreferenceDialogFragmentCompat();
Bundle bundle = new Bundle(1);
bundle.putString("key", preference.getKey());
dialogFragment.setArguments(bundle);
}
if (dialogFragment != null)
{
dialogFragment.setTargetFragment(this, 0);
dialogFragment.show(this.getFragmentManager(), "android.support.v7.preference.PreferenceFragment.DIALOG");
}
else
{
super.onDisplayPreferenceDialog(preference);
}
}
}
С вышеприведенным временем кода предпочтение можно использовать в файле xml предпочтений, подобном этому
<com.test.TimePreference
android:key="some_time"
android:title="Set some time"
android:defaultValue="12:00"
android:summary="Set some time"/>
Ответ 5
добавить это для сводки:
@Override
public CharSequence getSummary() {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH, lastHour, lastMinute);
return DateFormat.getTimeFormat(getContext()).format(new Date(cal.getTimeInMillis()));
}
и добавьте
setSummary(getSummary());
до конца onSetInitialValue и onDialogClosed.
Ответ 6
Решение CommonsWare имеет несколько проблем, которые я исправил:
- Он не обновляет поле правильно после его изменения.
- Значение минут сохраняется только на одну цифру, например. 10: 2 вместо 10:02
- Если вы используете PreferenceManager.setDefaultPreferences для установки начальных настроек по умолчанию в своем приложении, это не сработает, потому что onSetInitialValue необходимо сохранить его
- Форматирование результата не адаптировано к пользовательскому языку (например, США используют AM/PM)
Здесь мой код, наслаждайтесь.
public class TimePreference extends DialogPreference {
private int lastHour=0;
private int lastMinute=0;
private TimePicker picker=null;
public static int getHour(String time) {
String[] pieces=time.split(":");
return(Integer.parseInt(pieces[0]));
}
public static int getMinute(String time) {
String[] pieces=time.split(":");
return(Integer.parseInt(pieces[1]));
}
public TimePreference(Context ctxt, AttributeSet attrs) {
super(ctxt, attrs);
setPositiveButtonText("Set");
setNegativeButtonText("Cancel");
}
@Override
protected View onCreateDialogView() {
picker=new TimePicker(getContext());
return(picker);
}
@Override
protected void onBindDialogView(View v) {
super.onBindDialogView(v);
picker.setCurrentHour(lastHour);
picker.setCurrentMinute(lastMinute);
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
lastHour=picker.getCurrentHour();
lastMinute=picker.getCurrentMinute();
setSummary(getSummary());
String lastMinuteString = String.valueOf(lastMinute);
String time = String.valueOf(lastHour) + ":" + (lastMinuteString.length() == 1 ? "0" + lastMinuteString : lastMinuteString);
if (callChangeListener(time)) {
persistString(time);
}
}
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return(a.getString(index));
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
String time;
String defaultValueStr = (defaultValue != null) ? defaultValue.toString() : "00:00";
if (restoreValue)
time = getPersistedString(defaultValueStr);
else {
time = defaultValueStr;
if (shouldPersist())
persistString(defaultValueStr);
}
lastHour=getHour(time);
lastMinute=getMinute(time);
setSummary(getSummary());
}
@Override
public CharSequence getSummary() {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, lastHour);
cal.set(Calendar.MINUTE, lastMinute);
DateFormat sdf = SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT);
return sdf.format(cal.getTime());
}
}
Ответ 7
Я изменил ответ CommonsWare на использование библиотеки JodaTime:
import android.content.Context;
import android.content.res.TypedArray;
import android.preference.DialogPreference;
import android.support.annotation.NonNull;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TimePicker;
import org.joda.time.LocalTime;
public class TimePreference extends DialogPreference {
private int lastHour;
private int lastMinute;
private TimePicker picker;
public TimePreference(Context context, AttributeSet attrs) {
super(context, attrs);
setPositiveButtonText("Set");
setNegativeButtonText("Cancel");
}
@Override
protected View onCreateDialogView() {
picker = new TimePicker(getContext());
return(picker);
}
@Override
protected void onBindDialogView(@NonNull View v) {
super.onBindDialogView(v);
picker.setCurrentHour(lastHour);
picker.setCurrentMinute(lastMinute);
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
lastHour = picker.getCurrentHour();
lastMinute = picker.getCurrentMinute();
LocalTime localTime = new LocalTime(lastHour, lastMinute);
String time = localTime.toString();
if (callChangeListener(time)) {
persistString(time);
}
}
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return(a.getString(index));
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
LocalTime time;
if (restoreValue) {
if (defaultValue == null) {
time = LocalTime.parse(getPersistedString("08:00:00.000"));
}
else {
time = LocalTime.parse(getPersistedString(defaultValue.toString()));
}
} else {
time = LocalTime.parse(defaultValue.toString());
}
lastHour = time.getHourOfDay();
lastMinute = time.getMinuteOfHour();
}
}
Также вам нужно добавить пользовательскую настройку, как сказал Сикора.
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<EditTextPreference
android:key="editTextPref_Key"
android:title="@string/editTextPref_title"/>
<com.example.myapp.TimePreference
android:key="timePrefA_Key"
android:title="@string/timePrefA_title"/>
<com.example.myapp.TimePreference
android:key="timePrefB_Key"
android:title="@string/timePrefB_title"/>
</PreferenceScreen>
Ответ 8
В Android 6 "текущий час" и "текущая минута" устарели. Используйте это, чтобы обеспечить совместимость с Marshmallow:
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TimePicker;
public class TimePreference extends DialogPreference {
private int lastHour;
private int lastMinute;
private TimePicker picker;
public TimePreference(Context ctx, AttributeSet attrs) {
super(ctx, attrs);
setPositiveButtonText(ctx.getString(android.R.string.ok));
setNegativeButtonText(ctx.getString(android.R.string.cancel));
}
@Override
protected View onCreateDialogView() {
picker = new TimePicker(getContext());
picker.setIs24HourView(true);
return picker;
}
@SuppressWarnings("deprecation")
@Override
protected void onBindDialogView(View v) {
super.onBindDialogView(v);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
picker.setCurrentHour(lastHour);
picker.setCurrentMinute(lastMinute);
} else {
picker.setHour(lastHour);
picker.setMinute(lastMinute);
}
}
@SuppressWarnings("deprecation")
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
lastHour = picker.getCurrentHour();
lastMinute = picker.getCurrentMinute();
} else {
lastHour = picker.getHour();
lastMinute = picker.getMinute();
}
String time = String.valueOf(lastHour) + ":" + String.valueOf(lastMinute);
if (callChangeListener(time)) {
persistString(time);
}
}
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getString(index);
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
String time;
if (restoreValue) {
if (defaultValue == null) {
time = getPersistedString("00:00");
} else {
time = getPersistedString(defaultValue.toString());
}
} else {
time = defaultValue.toString();
}
lastHour = getHour(time);
lastMinute = getMinute(time);
}
public static int getHour(String time) {
String[] pieces = time.split(":");
return Integer.parseInt(pieces[0]);
}
public static int getMinute(String time) {
String[] pieces = time.split(":");
return Integer.parseInt(pieces[1]);
}
}
Ответ 9
Как и LEO87, я видел ClassCastException. Проблема состояла в том, что из-за устаревших данных сохранялось предыдущее управление с тем же именем. Возможные решения: очистить данные приложения, использовать другое имя (ключ) или использовать одно и то же имя ключа, перехватить исключение следующим образом:
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
if (restoreValue) {
long persistedValue;
try {
persistedValue = getPersistedLong(System.currentTimeMillis());
} catch (Exception e) {
//Stale persisted data may be the wrong type
persistedValue = System.currentTimeMillis();
}
calendar.setTimeInMillis(persistedValue);
} else if (defaultValue != null) {
calendar.setTimeInMillis(Long.parseLong((String) defaultValue));
} else {
//!restoreValue, defaultValue == null
calendar.setTimeInMillis(System.currentTimeMillis());
}
setSummary(getSummary());
}