前言
最近在弄一个小项目练练手,本来想着还是很简单的,结果一路碰壁,觉得一定要记下来,免得以后再被坑。(持续更新)
StackOverflow果然是一个神奇的网站,很多坑都可以在上面找到解决方案,当然,前提是要看得懂English,其实主要是会看代码即可,呵呵。
AlertDialog
我想点击按钮不关闭对话框
情景:
弹出一个对话框,用于输入密码,当点击按钮后,对密码进行校验,通过校验则关闭对话框,并继续后面的操作,当密码没通过校验时,只提示信息,不关闭对话框。
这是一个比较常用的情景(个人认为 - -),但是Google并没有提供相关的API来让开发者控制什么时候关闭对话框,而且API里面已经把这个写死了(Google这么设计肯定也有道理的,毕竟提示框的功能本来就是提示而已),不管点击的是哪个按钮(positive / neutral / negative),最终都会调用dismiss()
来关闭AlertDialog
。
这是OnClickListener
的定义:
private final View.OnClickListener mButtonHandler = new View.OnClickListener() {
@Override
public void onClick(View v) {
final Message m;
if (v == mButtonPositive && mButtonPositiveMessage != null) {
m = Message.obtain(mButtonPositiveMessage);
} else if (v == mButtonNegative && mButtonNegativeMessage != null) {
m = Message.obtain(mButtonNegativeMessage);
} else if (v == mButtonNeutral && mButtonNeutralMessage != null) {
m = Message.obtain(mButtonNeutralMessage);
} else {
m = null;
}
if (m != null) {
m.sendToTarget();
}
// Post a message so we dismiss after the above handlers are executed
mHandler.obtainMessage(ButtonHandler.MSG_DISMISS_DIALOG, mDialog)
.sendToTarget();
}
};
再看看这个Handler如何处理这个Message:
public void handleMessage(Message msg) {
switch (msg.what) {
case DialogInterface.BUTTON_POSITIVE:
case DialogInterface.BUTTON_NEGATIVE:
case DialogInterface.BUTTON_NEUTRAL:
((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what);
break;
case MSG_DISMISS_DIALOG:
((DialogInterface) msg.obj).dismiss(); // <<- 看这里
}
}
由此可见(注释已经写得很清楚了),在点击按钮后,AlertDialog
肯定会被关闭的。
既然看清内幕了,那么解决方案是什么呢?
重写
Button
的OnClickListener
:How to prevent a dialog from closing when a button is clicked
注意: getButton 必须在 create 或者 show 之后调用,否则抛出NullPointerException反射。(这是一个几乎可以解决任何问题大招)
通过反射,有好几种方法可以解决AlertDialog
的关闭问题。其中比较最简单的一种方法,就是修改Dialog
类中的mShowing
字段的值(这个对话框根本没显示呀,不需要dismiss了)。
定义一个设置mShowing的方法:
public void canCloseDialog(DialogInterface dialog, boolean close)
try {
Field field = dialog.getClass().getSuperclass().getDeclaredField("mShowing");
field.setAccessible(true);
field.set(dialog, close);
} catch (Exception e) {
e.printStackTrace();
}
然后这样使用就可以了:
new AlertDialog.Builder(this)
.setTitle("输入密码")
.setView(passwdEditText)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
canCloseDialog(dialogInterface, false); // false表示不关闭
}
})
.setNeutralButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
canCloseDialog(dialogInterface, true); // true表示会被关闭
}
})
.show();
本节到此结束,关于反射的其他方案就不说了,反正很少用到。