Ok everyone knows that to hide a keyboard you need to implement:
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hi
Just override below code in Activity
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (getCurrentFocus() != null) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), 0);
}
return super.dispatchTouchEvent(ev);
}
I'm aware that this thread is quite old, the correct answer seems valid and there are a lot of working solutions out there, but I think the approach stated bellow might have an additional benefit regarding efficiency and elegance.
I need this behavior for all of my activities, so I created a class CustomActivity inheriting from the class Activity and "hooked" the dispatchTouchEvent function. There are mainly two conditions to take care of:
This is my result:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if(ev.getAction() == MotionEvent.ACTION_UP) {
final View view = getCurrentFocus();
if(view != null) {
final boolean consumed = super.dispatchTouchEvent(ev);
final View viewTmp = getCurrentFocus();
final View viewNew = viewTmp != null ? viewTmp : view;
if(viewNew.equals(view)) {
final Rect rect = new Rect();
final int[] coordinates = new int[2];
view.getLocationOnScreen(coordinates);
rect.set(coordinates[0], coordinates[1], coordinates[0] + view.getWidth(), coordinates[1] + view.getHeight());
final int x = (int) ev.getX();
final int y = (int) ev.getY();
if(rect.contains(x, y)) {
return consumed;
}
}
else if(viewNew instanceof EditText || viewNew instanceof CustomEditText) {
return consumed;
}
final InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(viewNew.getWindowToken(), 0);
viewNew.clearFocus();
return consumed;
}
}
return super.dispatchTouchEvent(ev);
}
Side note: Additionally I assign these attributes to the root view making it possible to clear focus on every input field and preventing input fields gaining focus on activity startup (making the content view the "focus catcher"):
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final View view = findViewById(R.id.content);
view.setFocusable(true);
view.setFocusableInTouchMode(true);
}
its too simple, just make your recent layout clickable an focusable by this code:
android:id="@+id/loginParentLayout"
android:clickable="true"
android:focusableInTouchMode="true"
and then write a method and an OnClickListner for that layout , so that when the uppermost layout is touched any where it will call a method in which you will write code to dismiss keyboard. following is the code for both; // you have to write this in OnCreate()
yourLayout.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
hideKeyboard(view);
}
});
method called from listner:-
public void hideKeyboard(View view) {
InputMethodManager imm =(InputMethodManager)getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
Here's another variation on fje's answer that addresses the issues raised by sosite.
The idea here is to handle both the down and the up actions in the Activity's dispatchTouchEvent
method. On the down action, we make note of the currently focused view (if any) and whether the touch was inside it, saving both those bits of info for later.
On the up action, we first dispatch, to allow another view to potentially take focus. If after that, the currently focused view is the originally focused view, and the down touch was inside that view, then we leave the keyboard open.
If the currently focused view is different than the originally focused view and it's an EditText
, then we also leave the keyboard open.
Otherwise we close it.
So, to sum up, this works as follows:
EditText
, the keyboard stays openEditText
to another EditText
, the keyboard stays open (doesn't close/reopen)EditText
that is not another EditText
, the keyboard closesEditText
to bring up the contextual action bar (with the cut/copy/paste buttons), the keyboard stays open, even though the UP action took place outside the focused EditText
(which moved down to make room for the CAB). Note, though, that when you tap on a button in the CAB, it will close the keyboard. That may or may not be desirable; if you want to cut/copy from one field and paste to another, it would be. If you want to paste back into the same EditText
, it would not be.when the focused EditText
is at the bottom of the screen and you long-click on some text to select it, the EditText
keeps focus and therefore the keyboard opens like you want, because we do the "touch is within view bounds" check on the down action, not the up action.
private View focusedViewOnActionDown;
private boolean touchWasInsideFocusedView;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
focusedViewOnActionDown = getCurrentFocus();
if (focusedViewOnActionDown != null) {
final Rect rect = new Rect();
final int[] coordinates = new int[2];
focusedViewOnActionDown.getLocationOnScreen(coordinates);
rect.set(coordinates[0], coordinates[1],
coordinates[0] + focusedViewOnActionDown.getWidth(),
coordinates[1] + focusedViewOnActionDown.getHeight());
final int x = (int) ev.getX();
final int y = (int) ev.getY();
touchWasInsideFocusedView = rect.contains(x, y);
}
break;
case MotionEvent.ACTION_UP:
if (focusedViewOnActionDown != null) {
// dispatch to allow new view to (potentially) take focus
final boolean consumed = super.dispatchTouchEvent(ev);
final View currentFocus = getCurrentFocus();
// if the focus is still on the original view and the touch was inside that view,
// leave the keyboard open. Otherwise, if the focus is now on another view and that view
// is an EditText, also leave the keyboard open.
if (currentFocus.equals(focusedViewOnActionDown)) {
if (touchWasInsideFocusedView) {
return consumed;
}
} else if (currentFocus instanceof EditText) {
return consumed;
}
// the touch was outside the originally focused view and not inside another EditText,
// so close the keyboard
InputMethodManager inputMethodManager =
(InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(
focusedViewOnActionDown.getWindowToken(), 0);
focusedViewOnActionDown.clearFocus();
return consumed;
}
break;
}
return super.dispatchTouchEvent(ev);
}
Try to put stateHidden on as your activity windowSoftInputMode
value
http://developer.android.com/reference/android/R.attr.html#windowSoftInputMode
For example for your Activity:
this.getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
Method for show / hide soft keyboard
InputMethodManager inputMethodManager = (InputMethodManager) currentActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
if (isShow) {
if (currentActivity.getCurrentFocus() == null) {
inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
} else {
inputMethodManager.showSoftInput(currentActivity.getCurrentFocus(), InputMethodManager.SHOW_FORCED);
}
} else {
if (currentActivity.getCurrentFocus() == null) {
inputMethodManager.toggleSoftInput(InputMethodManager.HIDE_NOT_ALWAYS, 0);
} else {
inputMethodManager.hideSoftInputFromInputMethod(currentActivity.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
I hope they have been useful