据我所知,在使用 TimePickerDialog 时,Jelly Beans之前的版本有 Set 和 Cancel 按钮。 Jelly Beans只有 Done 按钮。
我可以离开 Done 按钮,然后点击对话框外部关闭对话框,但是如果按 Done 或在外面,我的onTimeSetListener
会被调用对话框。
所以我发现this stackoverflow question描述了使用 DatePickerDialog 时出现的错误。要使用 DatePickerDialog 解决问题,初始化时我必须将onDateSetListener
设置为null
,并实现我自己的按钮来处理BUTTON_POSITIVE
(设置)和BUTTON_NEGATIVE
(取消)onClick方法。哪个没问题,因为当调用按钮 Set 时,我可以访问 DatePicker 这样的值
int yearPicked = dateDlg.getDatePicker().getYear();
int monthPicked = dateDlg.getDatePicker().getMonth();
int dayPicked = dateDlg.getDatePicker().getDayOfMonth();
所以不需要使用onDateSetListener
,但是如果我愿意的话,按下Set或Cancel时会再次调用它。
我尝试以相同的方式使用 TimePickerDialog ,但问题是,在BUTTON_POSITIVE
onClick方法中,我无法像以前那样访问小时和分钟值,因为 TimePickerDialog 不提供 TimePicker ,因为 DatePickerDialog 提供 DatePicker 。再次,如果我使用onTimeSetListener
,可以通过按任何东西来调用它。
Calendar cal = Calendar.getInstance();
int hour = cal.get(Calendar.HOUR_OF_DAY);
int min = cal.get(Calendar.MINUTE);
final TimePickerDialog timeDlg = new TimePickerDialog(PreferencesActivity.this, null, hour, min, true);
// Make the Set button
timeDlg.setButton(DialogInterface.BUTTON_POSITIVE, "Set", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_POSITIVE) {
// CANNOT ACCES THE VALUES
Toast.makeText(PreferencesActivity.this, "Set", Toast.LENGTH_SHORT).show();
}
}
});
// Set the Cancel button
timeDlg.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_NEGATIVE) {
Toast.makeText(PreferencesActivity.this, "Cancel", Toast.LENGTH_SHORT).show();
}
}
});
timeDlg.show();
答案 0 :(得分:8)
根据您的评论,使用布尔值保护OnTimeSetListener
回调应该很容易,以防止在单击“取消”的情况下运行逻辑。
我快速玩了你的代码,以下似乎工作正常:
private boolean mIgnoreTimeSet = false;
final TimePickerDialog timeDlg = new TimePickerDialog(PreferencesActivity.this, PreferencesActivity.this, hour, min, true);
// Make the Set button
timeDlg.setButton(DialogInterface.BUTTON_POSITIVE, "Set", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
mIgnoreTimeSet = false;
// only manually invoke OnTimeSetListener (through the dialog) on pre-ICS devices
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) timeDlg.onClick(dialog, which);
Toast.makeText(getApplicationContext(), "Set", Toast.LENGTH_SHORT).show();
}
});
// Set the Cancel button
timeDlg.setButton(DialogInterface.BUTTON_NEGATIVE, "Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(getApplicationContext(), "Cancel", Toast.LENGTH_SHORT).show();
mIgnoreTimeSet = true;
dialog.cancel();
}
});
timeDlg.show();
@Override public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
if (mIgnoreTimeSet) return;
// get the values here - this will only run if 'Set' was clicked
}
为了示例,我假设您的PreferencesActivity
实现OnTimeSetListener
。由于在onTimeSet(...)
之后调用onClick(...)
,您只需切换一个布尔值,该布尔值将决定您是否应该对回调中的值执行某些操作,或者忽略它们。
我不得不同意它并不理想,但至少是功能性的。假期结束后,我会尝试再次寻找“更好”的解决方案。
一种替代方法是使用反射来获取内部使用的TimePicker
小部件的句柄,但这在未来的Android版本中更容易破解。
//编辑:潜在的替代方案? (未经测试)
第二种选择,可能有点'更清洁':扩展TimePickerDialog
并覆盖(空)公共方法:
public void onTimeChanged(TimePicker view, int hourOfDay, int minute)
在那里,跟踪日期和分钟的用户设置小时,并实现两个返回它们的getter。然后,如果点击了肯定按钮,则只从对话框中获取这些值,但只是为了“取消”。基本上你不再需要OnTimeSetListener
,因此无论是否被调用都无关紧要。
// Edit2:支持预ICS设备
在收到关于未在ICS前设备上工作的建议解决方案的几点评论之后,我对上述代码做了一些小改动 - 即使很难,也不在原始问题的范围内。
pre-ICS和post-ICS设备之间的主要区别在于,在运行对话框按钮的OnTimeSetListener
方法后,不会自动调用onClick()
回调。一个简单的解决方法是在对话框上调用onClick()
方法,然后调用侦听器。在上面的解决方案中,我添加了一个版本代码检查,因为否则你的监听器最终会在后ICS设备上被调用两次,这可能会导致不良的副作用。
在Android 2.1-update1和Android 4.2.2上经过测试和确认的行为。
答案 1 :(得分:1)
在我的Nexus 7(我的Nexus One,Gingerbread,同一个TimePickerDialog的Set和Cancel按钮)上遇到与Jelly Bean的TimePickerDialog相同的“Done-button-only”问题时,我找到了这个帖子。但是,随着我的Nexus 7(内部版本号JWR66Y)上的4.3 Jelly Bean的后续更新,似乎已经返回了正确的按钮Set和Cancel。
然而,在研究这个问题时,我确实遇到了这个Stackoverflow thread,它更精确地概述了DatePickerDialog的更大问题(在引用的错误报告中为TimePickerDialog指出了类似的问题)并提供了解决方案。
请注意,必须仔细考虑使用这些对话框,因为它们在某些Android版本中无法正常运行(根据作者的说法,上述线程中提供的解决方案未在生产代码中使用)。