PreferenceScreen中的TimePicker
我想要创build一个名为Interval
的首选项,我希望能够popup一个TimePicker
并设置一个mm:ss
格式的值,最小值为00:30
,步长为30秒。
PreferenceScreen
可以使用TimePicker
吗?
Android中没有内置TimePreference。 但是,创build自己的是相当容易的。 这是我做的一个 :
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); } }
我已经修改了第一个答案的代码:
- 它存储选定的时间长(毫秒),这是更容易使用(使用日历),然后string
- 它会以用户的格式(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())); } }
对于那些执行自定义偏好不太明显的人来说,你必须把这个添加到你的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
)
对于Preferences Support Library
需要不同的代码。 它需要两个自定义类TimePreference
和TimePreferenceDialogFragmentCompat
,以及PreferenceFragmentCompat
扩展类中的onDisplayPreferenceDialog
方法的覆盖。
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"/>
总结:
@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 。
我已经修改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(); } }
你也需要添加一个自定义的喜好,像Sikora说。
<?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>
使用Android 6时,“当前小时”和“当前分钟”不推荐使用。 使用这个来确保棉花糖的兼容性:
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]); } }
CommonsWare的解决scheme有一些问题,我解决了这个问题:
- 它在更改后不会正确更新字段
- 分钟值只保留一个数字,例如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()); } }
像LEO87,我看到ClassCastException的。 这个问题是由于过去的同一个名字控制的陈旧的持久数据造成的。 可能的解决scheme是清除应用程序数据,使用不同的名称(密钥),或者如果您必须使用相同的密钥名称,请按如下方式捕获exception:
@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()); }