前言
在使用繼承的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
