Android development: The correct way to use hidden keyboards in Dialog
Scene: A Dialog pops up, with an EditText inside it, used to enter the content. Because the keyboard needs to be popped up when inputting, so when the Dialog disappears, the keyboard needs to be hidden together.
Now let's make a custom Dialog
MyDialog extends Dialog
At first I thought this function was easy to implement, so I wrote the following code
// Write in Dialog constructor (new OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { hideKeyBoard(); } }); //edContent is the input box public void hideKeyBoard(){ InputMethodManager inputMethodManager = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); ((), InputMethodManager.HIDE_NOT_ALWAYS); }
After running, I found that it was impossible to hide it at all. Let's see what happened in hideSoftInputFromWindow
public boolean hideSoftInputFromWindow(IBinder windowToken, int flags, ResultReceiver resultReceiver) { checkFocus(); synchronized (mH) { if (mServedView == null || () != windowToken) { return false; } try { return (mClient, flags, resultReceiver); } catch (RemoteException e) { } return false; } }
After tracking, I found that the parameter windowToken is null, and mServedView is also null, so I directly return false and cannot be hidden.
In other words, it is not possible to listen to Cancel or Dismiss because Dialog has disappeared at this time and the service form used for input is already null. So if you want to hide the keyboard, you need to process it before Dismiss. So where is this entry?
In order to hide Dialog when clicking on a blank, we added a sentence to the constructor
(true);
So when we click on the blank area, the onTouchEvent of the Dialog will be triggered
public boolean onTouchEvent(MotionEvent event) { if (mCancelable && mShowing && (mContext, event)) { cancel(); return true; } return false; }
Here we will call the shouldCloseOnTouch method of the base class Window to determine whether it can be closed. Here we see that if it is satisfied, we will directly cancel().
public void cancel() { if (!mCanceled && mCancelMessage != null) { mCanceled = true; // Obtain a new message so this dialog can be re-used (mCancelMessage).sendToTarget(); } dismiss(); }
Dialog will be dismissed here, so we found that we could not interfere at all before dismiss, which is really a tragedy. So we can only overload the onTouchEvent method and determine whether it can be closed by ourselves (that is, migrate the following code to your code!
public boolean shouldCloseOnTouch(Context context, MotionEvent event) { if (mCloseOnTouchOutside && () == MotionEvent.ACTION_DOWN && isOutOfBounds(context, event) && peekDecorView() != null) { return true; } return false; } private boolean isOutOfBounds(Context context, MotionEvent event) { final int x = (int) (); final int y = (int) (); final int slop = (context).getScaledWindowTouchSlop(); final View decorView = getDecorView(); return (x < -slop) || (y < -slop) || (x > (()+slop)) || (y > (()+slop)); }
This is what it is in your own code
@Override public boolean onTouchEvent(MotionEvent event) { if (isShowing() && shouldCloseOnTouch(getContext(),event)){ hideKeyBoard(); } return (event); } public boolean shouldCloseOnTouch(Context context, MotionEvent event) { if (() == MotionEvent.ACTION_DOWN && isOutOfBounds(context, event) && getWindow().peekDecorView() != null) { return true; } return false; } private boolean isOutOfBounds(Context context, MotionEvent event) { final int x = (int) (); final int y = (int) (); final int slop = (context).getScaledWindowTouchSlop(); final View decorView = getWindow().getDecorView(); return (x < -slop) || (y < -slop) || (x > (()+slop)) || (y > (()+slop)); }
If you have any questions, please leave a message or go to the community of this site to exchange and discuss. Thank you for reading. I hope it can help you. Thank you for your support for this site!