大家都知道监听 Dialog 消失事件常常是要重写 onDismiss()
或者 onCancle()
方法,有时候为了让 Dialog 主动消失,我们会调用 Dialog 的 dismiss()
和 cancle()
方法。而一个 Dialog 的消失有三种方式可以设置:
- 默认的 Cancel 按键:
builder.setNegativeButton(android.R.string.cancel, null);
- 设置点击外面退出:
builder.create().setCanceledOnTouchOutside(true);
- 点击 Back 键
但是这三种方法是怎样让 Dialog 消失的?这个问题的答案通过查看相关源码来一探究竟。
setNegativeButton(android.R.string.cancel, null)
查看 Dialog 的 Click 的响应事件可以看到:
1 | private final View.OnClickListener mButtonHandler = new View.OnClickListener() { |
由于默认的方式没有设置 mButtonNegativeMessage,所以默认的 Cancel 按键执行的是
1 | mHandler.obtainMessage(ButtonHandler.MSG_DISMISS_DIALOG, mDialogInterface) |
从对应的 Handler 可以看到,这个 case 下,所执行的是 dismiss() 方法。
1 | case MSG_DISMISS_DIALOG: |
setCanceledOnTouchOutside
当设置为 true 的时候可以看到这个 Dialog 就被设置为 cancelable 的。
1 | public void setCanceledOnTouchOutside(boolean cancel) { |
可以看到 Dialog 范围外的 Touch 事件是由 Window 判断的。
1 | public void setCloseOnTouchOutside(boolean close) { |
通过查看 mCloseOnTouchOutside 的引用可以找到:
1 | public boolean shouldCloseOnTouch(Context context, MotionEvent event) { |
可以看到确实是由 Window 类响应了这个点击事件。查看该函数的引用则找到 Dialog 里的方法:
1 | public boolean onTouchEvent(MotionEvent event) { |
很明显,cancel()
方法就是要找的答案。
1 | public void cancel() { |
可以看到这和直接调用 dismiss()
方法是类似的,但是是先发送了一个 cancle 消息再调用 dismiss()
。
点击 Back 键
点击 Back 键就很简单,一目了然。
1 | public void onBackPressed() { |
同样的调用了 cancel 方法。
总结
cancel()
方法先发送 cancel 消息,再 dismiss()
,而 dismiss()
就是发送消息通知 WindowManager 立即移除 View, 接着发送 dismiss 消息。
简单跳转之后可以看到,每一个 AlertDialog 都注册了 cencel()
和 dismiss()
的 Listener,这也就是我们常常重写 onCencel()
和 onDismiss()
这两个方法的作用。
通过查看以上三种方式的源码,可以发现:
- 默认的 Cancel 按键:调用 dismiss 方法,即窗口消失、回调 onDismiss;
- 设置点击外面退出:调用 cancle 方法,即回调 onCancle、窗口消失、回调 onDismiss;
- 点击 Back 键:调用 cancle 方法,即回调 onCancle、窗口消失、回调 onDismiss;
因此要注意你需要复写的是哪个方法,如果使用默认的 Cancle 按键,复写 onCancle()
可是一点作用都没有呀。