前言
在使用继承的Dialog的方式实现自定义Dialog,如果这个Dialog我们还添加了EditText就会发现一个问题。在输入盘显示后,Dialog退出输入盘不会退出。网上有一些奇怪的解决办法,最奇怪的是去根据Touch事件判断Touch坐标来确定是否点击了空白在隐藏输入盘,绕了一个大圈来实现,根本就没仔细阅读过Dialog的代码。其实实现退出Dialog的时候隐藏输入法很简单,只要重写Dialog的dismiss()方法即可,为什么写这篇博客是因为不想大家被错误的实现方式而误导。所以,这里会啰嗦下问题根结。
了解Dialog的退出方式
在了解隐藏输入盘之前,需要排列一下Dialog的退出的3种方式:
1.自定义退出按键,点击后实现dialog.dismiss(); 退出对话框
2.按back键,退出对话框
3.点击Dialog外面的空白背景,退出对话框
错误的隐藏输入盘的方式
@Overridepublic voidonClickLeft(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.
*
*@paramevent The touch screen event being processed.
*@returnReturn 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 booleanonTouchEvent(@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 voidonBackPressed() {if(mCancelable) {
cancel();
}
}
最后都调用了cancel()方法,而cancel方法最后都调用了dismiss方法,但是这些回调都是用Handler发出去的,所以Dialog都已经关闭(并没有被销毁)与window解除了绑定关系了,才会接收到setOnDismissListener();方法 与 setOnCancelListener(); 这2个回调。所以在这2个回调里写隐藏输入盘也是错误的。
正确的方式
重写dismiss方法
@Overridepublic voiddismiss() {
InputMethodManager imm=(InputMethodManager) mEditContent.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mEditContent.getWindowToken(), InputMethodManager.RESULT_UNCHANGED_SHOWN);super.dismiss();
}
End
原文:https://www.cnblogs.com/guanxinjing/p/12980640.html