在日常开发中,Activity中可能有比较复杂的布局,比如嵌套很多Fragment,所以针对该需求,通常的做法为放到Activity中统一处理。
常规思路为在dispatchTouchEvent中不拦截MotionEvent,但是会根据event是否落在EditText中做相应的处理,具体做法为
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if (isShouldHideInput(v, ev)) {
hideInputMethod(this, v);
}
}
return super.dispatchTouchEvent(ev);
}
private boolean isShouldHideInput(View v, MotionEvent event) {
if (v != null && (v instanceof EditText)) {
int[] leftTop = {0, 0};
v.getLocationInWindow(leftTop);
int left = leftTop[0], top = leftTop[1], bottom = top + v.getHeight(), right = left
+
v.getWidth();
if (event.getX() > left && event.getX() < right
&& event.getY() > top && event.getY() < bottom) {
return false;
} else {
return true;
}
}
return false;
}
private Boolean hideInputMethod(Context context, View v) {
v.clearFocus();
InputMethodManager imm = (InputMethodManager)context
.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
return false;
}
在Down事件时如果event不在当前获取焦点的EditText中,则收起键盘,另外清除焦点,注意EditText的parent需要设置如下属性保证可以获取焦点,一般直接设置在activity的顶层布局中
android:focusable="trur"
android:focusableInTouchMode="trur"
如上处理后会发现用户在EditText间切换焦点时不正常,键盘会出现先收起再弹出,我们要做的是能判断MotionEvent消费后是否由其它EditText获取到了焦点,如果是的话则不收起键盘。
当用户点击其它EditText时,只有Up事件发生时才会完成focus切换,所以做法有两种,第一种比较简单,延时200ms再判断就可以覆盖绝大部分场景,不过会出现用户按住其它EditText时键盘收起等情况。
private boolean hideInputMethod(Context context, View v) {
// 延时100ms判断焦点是否还在edittext,不在的话则隐藏键盘
mHandler.postDelayed(() -> {
View current = getCurrentFocus();
if (current == v) {
v.clearFocus();
InputMethodManager imm = (InputMethodManager)context
.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
}
}, 200);
return false;
}
另外一个更好的方法是在dispatchTouchEvent中监听焦点的变化,如果down和up时焦点无变化,则认为需要收起键盘,与上面类似。具体代码如下
boolean pendingCollapseKeyword = false;
View focusedView;
// 点击非输入框位置优先隐藏软键盘
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
pendingCollapseKeyword = isShouldHideInput(ev);
if (pendingCollapseKeyword) focusedView = getCurrentFocus();
} else if (ev.getAction() == MotionEvent.ACTION_UP) {
if (pendingCollapseKeyword) {
hideInputMethod(this);
}
}
return super.dispatchTouchEvent(ev);
}
private boolean isShouldHideInput(MotionEvent event) {
View v = getCurrentFocus();
if (v instanceof EditText) {
int[] location = {0, 0};
v.getLocationInWindow(location);
return event.getX() < location[0]
|| event.getX() > location[0] + v.getWidth()
|| event.getY() < location[1]
|| event.getY() > location[1] + v.getHeight();
}
return false;
}
// 抬起手指时如果焦点还在原来的EditText则收起键盘
private void hideInputMethod(Context context) {
View v = getCurrentFocus();
if (v == focusedView) {
focusedView.clearFocus();
InputMethodManager imm = (InputMethodManager)context
.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(focusedView.getWindowToken(), 0);
}
}
}
如上同时兼顾了两个需求
- 点击EditText外收起键盘
- 点击其它EditText保持键盘状态不变