Ok everyone knows that to hide a keyboard you need to implement:
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.hi
I liked the approach of calling dispatchTouchEvent
made by htafoya, but:
So, I made this somewhat easier solution:
@Override
public boolean dispatchTouchEvent(final MotionEvent ev) {
// all touch events close the keyboard before they are processed except EditText instances.
// if focus is an EditText we need to check, if the touchevent was inside the focus editTexts
final View currentFocus = getCurrentFocus();
if (!(currentFocus instanceof EditText) || !isTouchInsideView(ev, currentFocus)) {
((InputMethodManager) getApplicationContext().getSystemService(Context.INPUT_METHOD_SERVICE))
.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
return super.dispatchTouchEvent(ev);
}
/**
* determine if the given motionevent is inside the given view.
*
* @param ev
* the given view
* @param currentFocus
* the motion event.
* @return if the given motionevent is inside the given view
*/
private boolean isTouchInsideView(final MotionEvent ev, final View currentFocus) {
final int[] loc = new int[2];
currentFocus.getLocationOnScreen(loc);
return ev.getRawX() > loc[0] && ev.getRawY() > loc[1] && ev.getRawX() < (loc[0] + currentFocus.getWidth())
&& ev.getRawY() < (loc[1] + currentFocus.getHeight());
}
There is one disadvantage:
Switching from one EditText
to another EditText
makes the keyboard hide and reshow - in my case it's desired that way, because it shows that you switched between two input components.
I got one more solution to hide the keyboard by:
InputMethodManager imm = (InputMethodManager) getSystemService(
Activity.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
Here pass HIDE_IMPLICIT_ONLY
at the position of showFlag
and 0
at the position of hiddenFlag
.
It will forcefully close the soft keyboard.
I modified the solution of Andre Luis IM I achieved this one:
I created a utility method to hide the soft keyboard the same way Andre Luiz IM did:
public static void hideSoftKeyboard(Activity activity) {
InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
}
But instead of register an OnTouchListener for every view, that give a poor performance, I registered the OnTouchListener for just the root view. Since the event bubbles until it's consumed (EditText is one of the views that consumes it by default), if it arrives to the root view, it's because it wasn't consumed, so I close the soft keyboard.
findViewById(android.R.id.content).setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Utils.hideSoftKeyboard(activity);
return false;
}
});
I implemented dispatchTouchEvent in Activity to do this:
private EditText mEditText;
private Rect mRect = new Rect();
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
final int action = MotionEventCompat.getActionMasked(ev);
int[] location = new int[2];
mEditText.getLocationOnScreen(location);
mRect.left = location[0];
mRect.top = location[1];
mRect.right = location[0] + mEditText.getWidth();
mRect.bottom = location[1] + mEditText.getHeight();
int x = (int) ev.getX();
int y = (int) ev.getY();
if (action == MotionEvent.ACTION_DOWN && !mRect.contains(x, y)) {
InputMethodManager input = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
input.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
}
return super.dispatchTouchEvent(ev);
}
and I tested it, works perfect!
I have refined the method, put the following code in some UI utility class(preferably, not necessarily) so that it can be accessed from all your Activity or Fragment classes to serve its purpose.
public static void serachAndHideSoftKeybordFromView(View view, final Activity act) {
if(!(view instanceof EditText)) {
view.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
hideSoftKeyboard(act);
return false;
}
});
}
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
View nextViewInHierarchy = ((ViewGroup) view).getChildAt(i);
serachAndHideSoftKeybordFromView(nextViewInHierarchy, act);
}
}
}
public static void hideSoftKeyboard (Activity activity) {
InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
}
Then say for example you need to call it from activity, call it as follows;
UIutils.serachAndHideSoftKeybordFromView(findViewById(android.R.id.content), YourActivityName.this);
Notice
findViewById(android.R.id.content)
This gives us the root view of the current group(you mustn't have set the id on root view).
Cheers :)
To solve this problem what you have to do is first use setOnFocusChangeListener of that Edittext
edittext.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
Log.d("focus", "focus loosed");
// Do whatever you want here
} else {
Log.d("focus", "focused");
}
}
});
and then what you need to do is override dispatchTouchEvent in the activity which contains that Edittext see below code
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if ( v instanceof EditText) {
Rect outRect = new Rect();
v.getGlobalVisibleRect(outRect);
if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
Log.d("focus", "touchevent");
v.clearFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
}
return super.dispatchTouchEvent(event);
}
Now what will happen is when a user click outside then firstly this dispatchTouchEvent will get called which then will clear focus from the editext now your OnFocusChangeListener will get called that focus has been changed now here you can do anything which you wanted to do hope it works