Android开发 在用EditText对话框Dialog退出后实现输入盘的退出

前言

  在使用继承的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

原文地址:https://www.cnblogs.com/guanxinjing/p/12980640.html