1
有时候我们需要禁用AlertDialog的按键。
一般情况下我们会利用AlertDialog的getButton接口获取到对应的Button,
然后调用Button的setEnabled接口,例如:
................
alertDialog.show();
alertDialog.getButton(
AlertDialog.BUTTON_POSITIVE).setEnabled(false);
................
注意这里有个限制,就是必须等到AlertDialog调用show接口后,
才能获取到Button对象,对应的分析可以参考链接。
2
除了上述方法外,是否还有其它方法可以在AlertDialog显示时禁用其按键呢?
答案是利用AlertDialog父类Dialog中的setOnShowListener接口。
其用法类似于:
...........
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(this);
//可进行一些设置
...........
//创建出AlertDialog
AlertDialog alertDialog = alertBuilder.create();
//设置OnShowListener
alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
//AlertDialog显示后,就会立马回调OnShowListener的onShow接口
@Override
public void onShow(DialogInterface dialog) {
//dialog就是创建出的dialog
((AlertDialog)dialog).getButton(
AlertDialog.BUTTON_POSITIVE).setEnabled(false);
}
});
//alertBuilder.show(); 不要这样
alertDialog.show();
............
setOnShowListener接口的用法还是很简单的,但也有两个需要注意的地方。
2.1
setOnShowListener必须在AlertDialog调用show接口之前设置,否则不会进行回调。
这里实现的不是一种粘性(sticky)的回调策略。
我们看看源码中Dialog的setOnShowListener接口:
............
public void setOnShowListener(@Nullable OnShowListener listener) {
if (listener != null) {
//注意,只是创建了一个Message
mShowMessage = mListenersHandler.obtainMessage(SHOW, listener);
} else {
//默认是null
mShowMessage = null;
}
}
.............
再来看看Dialog的show接口:
public void show() {
if (mShowing) {
...........
return;
}
//组件等的创建
...........
mWindowManager.addView(mDecor, l);
mShowing = true;
sendShowMessage();
}
private void sendShowMessage() {
if (mShowMessage != null) {
// Obtain a new message so this dialog can be re-used
//发送消息给ListenersHandler,回调Listener的接口
Message.obtain(mShowMessage).sendToTarget();
}
}
由于sendShowMessage函数,只有在AlertDialog调用show的时候才会被调用。
因此如果在show之前,没有注册OnShowListener生成mShowMessage,
却在show后注册OnShowListener,该Listener并不会被回调。
2.2
调用AlertDialog.Builder的create接口创建AlertDialog后,
如果在该AlertDialog上设置Listener,就必须在该AlertDialog上调用show接口。
不能再使用AlertDialog.Builder的show接口。
我们看看源码就知道原因:
public AlertDialog show() {
//重新创建出一个新的dialog
final AlertDialog dialog = create();
//然后show
dialog.show();
return dialog;
}
因此,如果在create接口创建出的dialog上增加Listener,
然后调用AlertDialog.Builder的show接口,那么之前的Listener不会被回调。
因为create接口创建出的dialog压根没被用到。
这个问题的原理很简单,但不注意的话还是会忽视的,
自己解bug时就发现过这个问题,好像是MTK写的代码(非黑)。