前言
在使用继承的Dialog的方式实现自定义Dialog,如果这个Dialog我们还添加了EditText就会发现一个问题。在输入盘显示后,Dialog退出输入盘不会退出。网上有一些奇怪的解决办法,最奇怪的是去根据Touch事件判断Touch坐标来确定是否点击了空白在隐藏输入盘,绕了一个大圈来实现,根本就没仔细阅读过Dialog的代码。其实实现退出Dialog的时候隐藏输入法很简单,只要重写Dialog的dismiss()方法即可,为什么写这篇博客是因为不想大家被错误的实现方式而误导。所以,这里会啰嗦下问题根结。
了解Dialog的退出方式
在了解隐藏输入盘之前,需要排列一下Dialog的退出的3种方式:
1.自定义退出按键,点击后实现dialog.dismiss(); 退出对话框
2.按back键,退出对话框
3.点击Dialog外面的空白背景,退出对话框
错误的隐藏输入盘的方式
@Override public void onClickLeft(EditDialog dialog) { dialog.dismiss(); InputMethodManager imm = (InputMethodManager) dialog.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(dialog.getEditContent().getWindowToken(), InputMethodManager.RESULT_UNCHANGED_SHOWN); }
说说为什么这种方式有问题,其实是因为你调用了dialog.dismiss(); 后在获取dialog.getEditContent().getWindowToken() 这个token的时候,必定会返回为null。 因为你的Dialog已经退出了。这个EditText已经被Window解除关系。所以我们需要在dimiss方法之前隐藏输入盘。
容易被误导难点在哪里?
看了上面的错误例子,我们肯定会在隐藏输入法后在调用dismiss(); 好像问题已经解决了? 并没有,因为你只解决了第一种情况 ”自定义退出按键,点击后实现dialog.dismiss(); 退出对话框“ ,还有
”按back键,退出对话框“
”点击Dialog外面的空白背景,退出对话框“
这2个情况的调用是Dialog直接在内部封装调用了dismiss(); 你无法在获取在dismiss之前操作隐藏输入盘。 setOnDismissListener();方法 与 setOnCancelListener();方法 都是执行完dismiss();方法后调用的。这里下面的源码中看到
按外部空白退出的方式
/** * Called when a touch screen event was not handled by any of the views * under it. This is most useful to process touch events that happen outside * of your window bounds, where there is no view to receive it. * * @param event The touch screen event being processed. * @return Return true if you have consumed the event, false if you haven‘t. * The default implementation will cancel the dialog when a touch * happens outside of the window bounds. */ public boolean onTouchEvent(@NonNull MotionEvent event) { if (mCancelable && mShowing && mWindow.shouldCloseOnTouch(mContext, event)) { cancel(); return true; } return false; }
按返回键退出的方式
/** * Called when the dialog has detected the user‘s press of the back * key. The default implementation simply cancels the dialog (only if * it is cancelable), but you can override this to do whatever you want. */ public void onBackPressed() { if (mCancelable) { cancel(); } }
最后都调用了cancel()方法,而cancel方法最后都调用了dismiss方法,但是这些回调都是用Handler发出去的,所以Dialog都已经关闭(并没有被销毁)与window解除了绑定关系了,才会接收到 setOnDismissListener();方法 与 setOnCancelListener(); 这2个回调。所以在这2个回调里写隐藏输入盘也是错误的。
正确的方式
重写dismiss方法
@Override public void dismiss() { InputMethodManager imm = (InputMethodManager) mEditContent.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(mEditContent.getWindowToken(), InputMethodManager.RESULT_UNCHANGED_SHOWN); super.dismiss(); }
End