我正在编写一个需要基于TimePicker的首选项(实际上是两个)的应用程序,并从Android Programming Tutorials书中刷了一些(Apache许可的)代码。我把它修改得更好一些,但有一件事令我困惑。
我还没有在实际设备上尝试过它,但是在仿真器上它现在考虑了24小时时间显示的系统设置,清除了对TimePicker对话框的关注,这样即使手动编辑而不是使用时间也会被读取箭头键和 - 有问题的部分 - 在PreferenceScreen中显示所选时间。
问题在于我已经在模拟器中尝试了这个API级别3,4,7和10,并且它只在10中完全正确工作。在早期版本的模拟器中,如果我在PreferenceScreen中放入一个复选框两个TimePreferences,每次切换复选框时,两个TimePreferences中的TextView都会切换位置。因此,如果我第一次启动应用程序时单击复选框,则开始时间看起来像晚上10点,停止时间看起来像早上8点(即使我点击首选项时,适当的时间显示在TimePicker中)。
有更好的方法吗?最好是一种优雅的方式,以便整个类是自包含的,我不需要在仅适用于类的XML文件中创建布局?或者有办法解决/修复此行为?我还想避免使用setSummary,以便仍然有机会向首选项添加摘要。我的大部分实验都在使用布局代码在onCreateView中,但我无法完全正确地工作。无论我使用RelativeLayout还是LinearLayout,这似乎都会发生。
完整代码如下:
package test.android.testproject2;
//imports...
public class TimePreference extends DialogPreference {
private int lastHour=0;
private int lastMinute=0;
private boolean is24HourFormat;
private TimePicker picker=null;
private TextView timeDisplay;
public TimePreference(Context ctxt) {
this(ctxt, null);
}
public TimePreference(Context ctxt, AttributeSet attrs) {
this(ctxt, attrs, 0);
}
public TimePreference(Context ctxt, AttributeSet attrs, int defStyle) {
super(ctxt, attrs, defStyle);
is24HourFormat = DateFormat.is24HourFormat(ctxt);
setPositiveButtonText("Set");
setNegativeButtonText("Cancel");
}
@Override
public String toString() {
if(is24HourFormat) {
return ((lastHour < 10) ? "0" : "")
+ Integer.toString(lastHour)
+ ":" + ((lastMinute < 10) ? "0" : "")
+ Integer.toString(lastMinute);
} else {
int myHour = lastHour % 12;
return ((myHour == 0) ? "12" : ((myHour < 10) ? "0" : "") + Integer.toString(myHour))
+ ":" + ((lastMinute < 10) ? "0" : "")
+ Integer.toString(lastMinute)
+ ((lastHour >= 12) ? " PM" : " AM");
}
}
@Override
protected View onCreateDialogView() {
picker=new TimePicker(getContext().getApplicationContext());
return(picker);
}
@Override
protected void onBindDialogView(View v) {
super.onBindDialogView(v);
picker.setIs24HourView(is24HourFormat);
picker.setCurrentHour(lastHour);
picker.setCurrentMinute(lastMinute);
}
@Override
protected View onCreateView (ViewGroup parent) {
View prefView = super.onCreateView(parent);
LinearLayout layout = new LinearLayout(parent.getContext());
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.FILL_PARENT, 2);
layout.addView(prefView, lp);
timeDisplay = new TextView(parent.getContext());
timeDisplay.setGravity(Gravity.BOTTOM | Gravity.RIGHT);
timeDisplay.setText(toString());
LinearLayout.LayoutParams lp2 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.FILL_PARENT, 1);
layout.addView(timeDisplay, lp2);
return layout;
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
picker.clearFocus();
lastHour=picker.getCurrentHour();
lastMinute=picker.getCurrentMinute();
String time=String.valueOf(lastHour)+":"+String.valueOf(lastMinute);
if (callChangeListener(time)) {
persistString(time);
timeDisplay.setText(toString());
}
}
}
@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 {
if (defaultValue==null) {
time="00:00";
}
else {
time=defaultValue.toString();
}
if (shouldPersist()) {
persistString(time);
}
}
String[] timeParts=time.split(":");
lastHour=Integer.parseInt(timeParts[0]);
lastMinute=Integer.parseInt(timeParts[1]);;
}
}
示例首选项布局如下:
<?xml version="1.0" encoding="UTF-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="@string/preferences_time_title">
<test.android.testproject2.TimePreference
android:key="preferences_start_time"
android:showDefault="true"
android:defaultValue="08:00"
android:summary="When to start"
android:title="@string/preferences_start_time"/>
<test.android.testproject2.TimePreference
android:key="preferences_stop_time"
android:showDefault="true"
android:defaultValue="22:00"
android:summary="When to stop"
android:title="@string/preferences_stop_time"/>
</PreferenceCategory>
<PreferenceCategory android:title="@string/preferences_options_title">
<CheckBoxPreference
android:key="preferences_enabled"
android:defaultValue="false"
android:title="@string/preferences_enabled"/>
</PreferenceCategory>
</PreferenceScreen>
截图:
这发生在API 3,4和7的模拟器上。我也在10上尝试过它并且它可以正常工作。
更新:它在带有API 8的模拟器上也能正常工作(2.2 / Froyo)。
更新2:我已经重写了onCreateView
方法,如下所示。它仍然以同样的方式失败,但渲染效率更高,我相信它的行为更接近Android文档中指定的要求。
@Override
protected View onCreateView (ViewGroup parent) {
ViewGroup prefView = (ViewGroup) super.onCreateView(parent);
View widgetLayout;
int childCounter = 0;
do {
widgetLayout = prefView.getChildAt(childCounter);
childCounter++;
} while (widgetLayout.getId() != android.R.id.widget_frame);
timeDisplay = new TextView(widgetLayout.getContext());
timeDisplay.setText(toString());
((ViewGroup) widgetLayout).addView(timeDisplay);
return prefView;
}
我的下一步是开始登录onCreateView,onBindView和getView,看看它们是如何被调用的以及视图内部发生了什么。如果有人在此期间提出任何想法,请告诉我!
答案 0 :(得分:3)
我已经弄明白了并修复了它。它现在适用于从Cupcake(1.5 - 3级)到Gingerbread(2.3.3 - 10级)的API的各个级别。代码如下。请注意,原始代码是在问题中指定的Apache许可。我特此将所有修改都用于公共领域。
package test.android.testproject2;
import android.content.Context;
import android.content.res.TypedArray;
import android.preference.DialogPreference;
import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.TimePicker;
public class TimePreference extends DialogPreference {
protected int lastHour=0;
protected int lastMinute=0;
protected boolean is24HourFormat;
protected TimePicker picker=null;
protected TextView timeDisplay;
public TimePreference(Context ctxt) {
this(ctxt, null);
}
public TimePreference(Context ctxt, AttributeSet attrs) {
this(ctxt, attrs, 0);
}
public TimePreference(Context ctxt, AttributeSet attrs, int defStyle) {
super(ctxt, attrs, defStyle);
is24HourFormat = DateFormat.is24HourFormat(ctxt);
setPositiveButtonText("Set");
setNegativeButtonText("Cancel");
}
@Override
public String toString() {
if(is24HourFormat) {
return ((lastHour < 10) ? "0" : "")
+ Integer.toString(lastHour)
+ ":" + ((lastMinute < 10) ? "0" : "")
+ Integer.toString(lastMinute);
} else {
int myHour = lastHour % 12;
return ((myHour == 0) ? "12" : ((myHour < 10) ? "0" : "") + Integer.toString(myHour))
+ ":" + ((lastMinute < 10) ? "0" : "")
+ Integer.toString(lastMinute)
+ ((lastHour >= 12) ? " PM" : " AM");
}
}
@Override
protected View onCreateDialogView() {
picker=new TimePicker(getContext().getApplicationContext());
return(picker);
}
@Override
protected void onBindDialogView(View v) {
super.onBindDialogView(v);
picker.setIs24HourView(is24HourFormat);
picker.setCurrentHour(lastHour);
picker.setCurrentMinute(lastMinute);
}
@Override
public void onBindView(View view) {
View widgetLayout;
int childCounter = 0;
do {
widgetLayout = ((ViewGroup) view).getChildAt(childCounter);
childCounter++;
} while (widgetLayout.getId() != android.R.id.widget_frame);
((ViewGroup) widgetLayout).removeAllViews();
timeDisplay = new TextView(widgetLayout.getContext());
timeDisplay.setText(toString());
((ViewGroup) widgetLayout).addView(timeDisplay);
super.onBindView(view);
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
picker.clearFocus();
lastHour=picker.getCurrentHour();
lastMinute=picker.getCurrentMinute();
String time=String.valueOf(lastHour)+":"+String.valueOf(lastMinute);
if (callChangeListener(time)) {
persistString(time);
timeDisplay.setText(toString());
}
}
}
@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 {
if (defaultValue==null) {
time="00:00";
}
else {
time=defaultValue.toString();
}
if (shouldPersist()) {
persistString(time);
}
}
String[] timeParts=time.split(":");
lastHour=Integer.parseInt(timeParts[0]);
lastMinute=Integer.parseInt(timeParts[1]);;
}
}