有没有一种方法使用取消Android的软糖TimePickerDialog?软糖、方法、Android、TimePickerDialog

2023-09-06 04:33:12 作者:時光戀人i

据我所知,之前的版本果冻豆,有设置和在使用取消按钮 TimePickerDialog 。糖豆只有完成按钮。

我可以离开完成按钮,可以通过单击对话外关闭对话框,但我的 onTimeSetListener 被调用,如果pressing 完成或对话外。

所以,我发现this计算器问题描述,当使用有一个错误的 DatePickerDialog 。要使用修复该问题的 DatePickerDialog ,初始化时我不得不设置 onDateSetListener ,并实现我自己的按钮来处理 BUTTON_POSITIVE (设置)和 BUTTON_NEGATIVE (取消)的onClick方法。这是很好的,因为当按钮设置叫我可以访问的的DatePicker 这样的值

  INT yearPicked = dateDlg.getDatePicker()得到年()。
INT monthPicked = dateDlg.getDatePicker()得到月()。
INT dayPicked = dateDlg.getDatePicker()getDayOfMonth()。
 

因此​​,有没有必要使用 onDateSetListener ,但如果我想,这将再次被调用时,pressing设置或取消。

我试图使用 TimePickerDialog 以同样的方式,但问题是, BUTTON_POSITIVE 的onClick方法中,我无法访问小时和分钟值和以前一样,因为 TimePickerDialog 不提供 TimePicker 作为 DatePickerDialog 提供的的DatePicker 。而且,如果再我会用 onTimeSetListener ,它会由pressing什么叫。

 日历CAL = Calendar.getInstance();

INT小时= cal.get(Calendar.HOUR_OF_DAY);
INT分钟= cal.get(Calendar.MINUTE);

最后TimePickerDialog timeDlg =新TimePickerDialog(preferencesActivity.this,空,小时,分钟,真正的);

//使设置按钮
timeDlg.setButton(DialogInterface.BUTTON_POSITIVE,设置,新DialogInterface.OnClickListener(){
    公共无效的onClick(DialogInterface对话,诠释它){
        如果(这== DialogInterface.BUTTON_POSITIVE){
            // CAN NOT ACCES的价值观
            Toast.makeText(preferencesActivity.this,设置,Toast.LENGTH_SHORT).show();
        }
    }
});


//设置取消按钮
timeDlg.setButton(DialogInterface.BUTTON_NEGATIVE,取消,新DialogInterface.OnClickListener(){
    公共无效的onClick(DialogInterface对话,诠释它){
        如果(这== DialogInterface.BUTTON_NEGATIVE){
            Toast.makeText(preferencesActivity.this,取消,Toast.LENGTH_SHORT).show();
        }
    }
});

timeDlg.show();
 

解决方案 一个自定义的Android日期时间选择器 DateTimePicker

根据您的意见,它应该是很容易守卫 OnTimeSetListener 回调一个布尔值,$ p $从的情况下取消点击运行pvent你的逻辑。

我有一个快速播放你的code和下面似乎工作好吗:

 私人布尔mIgnoreTimeSet = FALSE;

最后TimePickerDialog timeDlg =新TimePickerDialog(preferencesActivity.this,preferencesActivity.this,小时,分钟,真正的);

//使设置按钮
timeDlg.setButton(DialogInterface.BUTTON_POSITIVE,设置,新DialogInterface.OnClickListener(){
    公共无效的onClick(DialogInterface对话,诠释它){
        mIgnoreTimeSet = FALSE;
        //仅在pre-ICS设备手动调用OnTimeSetListener(通过对话)
        如果(Build.VERSION.SDK_INT< Build.VERSION_ codeS.ICE_CREAM_SANDWICH)timeDlg.onClick(对话框,该对话框);
        Toast.makeText(getApplicationContext(),设置,Toast.LENGTH_SHORT).show();
    }
});

//设置取消按钮
timeDlg.setButton(DialogInterface.BUTTON_NEGATIVE,取消,新DialogInterface.OnClickListener(){
    公共无效的onClick(DialogInterface对话,诠释它){
        Toast.makeText(getApplicationContext(),取消,Toast.LENGTH_SHORT).show();
        mIgnoreTimeSet = TRUE;
        dialog.cancel();
    }
});

timeDlg.show();

@覆盖公共无效onTimeSet(TimePicker观点,诠释hourOfDay,INT分钟){
    如果(mIgnoreTimeSet)回报;
    //获取值在这里 - 这会出现设置被点击只运行
}
 

为了这个例子中,我假定你的 preferencesActivity 工具 OnTimeSetListener 。由于 onTimeSet(...)被调用的onClick(...),你可以简单地切换一个布尔值,将决定你是否应该做一些与价值观在回调或只是忽略它们。

我不得不承认这是不理想,但至少功能。假期后,我会尽力在一个'好'的解决方案再看一看。

一种选择是使用反射来获取的内部使用 TimePicker 控件的句柄,但更可能在未来的Andr​​oid版本打破。

//编辑:潜在的替代? (未测试)

第二个选择,这可能是一个有点'清洁':延长 TimePickerDialog 和覆盖(空)的公共方法:

 公共无效onTimeChanged(TimePicker观点,诠释hourOfDay,INT分钟)
 

在那里,跟踪一天和分钟的用户设置的小时和实现了两个getter方法​​返回它们。那么只有从对话框中获取这些值,如果积极的按钮被点击,只是落空了取消。基本上,你再不会需要一个 OnTimeSetListener 了,因此它不会不管它是否是曾经被称为与否。

// EDIT2:支持pre-ICS设备

收到一对夫妇有关建议的解决方案不工作的pre-ICS设备的言论之后,我做了小改动上述code - 即使辛苦也没有原来质询的范围

pre-ICS和post-ICS设备之间的主要区别是, OnTimeSetListener 回调不会自动后您的对话框按钮的的onClick()办法(S)运行。一个简单的解决方法是调用的onClick()的对话框,然后将调用监听器的方法。在上面的解决方案,我添加了一个版本,code检,否则你的听众会最终被称为两次后ICS的设备,这可能会导致不希望的副作用。

经过测试,确认行为在Android 2.1 UPDATE1和Android 4.2.2。

As far as I am aware, versions prior to Jelly Beans, had Set and Cancel buttons when using TimePickerDialog. Jelly Beans has only Done button.

I could just leave the Done button, and could close the dialog by clicking outside the dialog, but my onTimeSetListener gets called if pressing Done or outside the dialog.

So I found this stackoverflow question which describes, that there is a bug when using DatePickerDialog. To fix the issue using DatePickerDialog, when initializing I had to set the onDateSetListener to null, and implement my own buttons to handle the BUTTON_POSITIVE (Set) and BUTTON_NEGATIVE (Cancel) onClick method. Which is fine, because when button Set is called I can access the DatePicker values like this

int yearPicked = dateDlg.getDatePicker().getYear();
int monthPicked = dateDlg.getDatePicker().getMonth();
int dayPicked = dateDlg.getDatePicker().getDayOfMonth();

So there is no need to use onDateSetListener, but if I would, it would again be called when pressing Set or Cancel.

I tried to use TimePickerDialog the same way, but the problem is, that inside BUTTON_POSITIVE onClick method, I cannot access the hour and minutes values as before, because TimePickerDialog does not provide TimePicker as DatePickerDialog provides DatePicker. And again if I would used onTimeSetListener, it would be called by pressing anything.

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

解决方案

Based on your comment, it should be easy enough to guard the OnTimeSetListener callback with a boolean to prevent your logic from running in the case 'Cancel' is clicked.

I had a quick play with your code, and the following seemed to work alright:

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
}

For the sake of the example, I've assumed your PreferencesActivity implements OnTimeSetListener. Since onTimeSet(...) gets called after onClick(...), you can simply toggle a boolean that will determine whether you should do something with the values in the callback or just ignore them.

I have to agree it's not ideal, but at least functional. After the holidays I'll try to have another look in a 'better' solution.

One alternative would be to use reflection to get a handle on the internally used TimePicker widget, but that's more likely to break in future Android releases.

// Edit: Potential alternative? (not tested)

Second alternative, which might be a bit 'cleaner': extend TimePickerDialog and overwrite the (empty) public method:

public void onTimeChanged(TimePicker view, int hourOfDay, int minute)

In there, keep track of the user-set hour of the day and minute and implement two getters that return them. Then only get these values from the dialog if the positive button gets clicked, but just fall through for 'Cancel'. Basically you then won't need an OnTimeSetListener anymore, and hence it won't matter whether it is ever gets called or not.

// Edit2: Support for pre-ICS devices

After receiving a couple of remarks about the proposed solution not working on pre-ICS devices, I made a small change to the above code - even tough it wasn't within the scope of the original question.

The main difference between pre-ICS and post-ICS devices is that the OnTimeSetListener callback isn't automatically invoked after your dialog button's onClick() method(s) is run. A simple workaround for that is to call the onClick() method on the dialog, which will then call the listener. In the solution above, I've added a version code check, because otherwise your listener will end up being called twice on post-ICS devices, which may lead to undesired side-effects.

Tested and confirmed behaviour on Android 2.1-update1 and Android 4.2.2.