android中并没有暴露给我们监听键盘弹出和收起的方法,为了监听键盘我们只能来监听界面的高度变化,这个大前提是不会变的,以前的方法是自定义最外层的Layout,并在onLayout方法中进行判断,但这样的判断有的时候是不准确的。为此我想到通过监听DecorView的Layoutchange方法中,比较DecorView和屏幕真正高度的来判断键盘的状态。为了能有这个变化我们用了SOFT_INPUT_ADJUST_PAN这个属性,以前判断键盘弹出都将这里设置成了SOFT_INPUT_ADJUST_RESIZE这属性,但是这个属性在RecyclerView中很可能会造成挡住输入框的情况。这也是在项目中遇到的坑才有了这个想法。代码如下:
public class MainActivity extends AppCompatActivity {
public static final int STATUS_SHOW = 201;
public static final int STATUS_HIDE = 202;
public static final int STATUS_CLICK_OTHER = 203;
private static final DisplayMetrics displayMetrics = new DisplayMetrics();
public String TGA= MainActivity.class.getName();
private int KeyStatus;
BaseAdapter adapter;
private RecyclerView mRecycler;
private Activity mContext;
private boolean isFirst;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN
| WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
setContentView(R.layout.activity_main);
getWindowManager().getDefaultDisplay()
.getMetrics(displayMetrics);
mRecycler = (RecyclerView)findViewById(R.id.Recycler);
mContext = this;
ArrayList list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
list.add("6");
adapter = new BaseAdapter(mContext);
adapter.lists = list;
mRecycler.setLayoutManager(new LinearLayoutManager(mContext));
mRecycler.setAdapter(adapter);
final int tempheight = displayMetrics.heightPixels / 4;
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
getWindow().getDecorView().addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
Rect rect = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
if(bottom != 0 && oldBottom != 0 && bottom - rect.bottom <= 0 && KeyStatus != STATUS_HIDE) {
Toast.makeText(mContext,"键盘消失",Toast.LENGTH_SHORT).show();
Log.d(TGA,"键盘消失");
if(isFirst){
isFirst = false;
return;
}
KeyStatus = STATUS_HIDE;
}else
if(bottom!=0 && oldBottom!=0 && bottom - rect.bottom > tempheight && KeyStatus != STATUS_SHOW){
Toast.makeText(mContext,"弹出键盘",Toast.LENGTH_SHORT).show();
Log.d(TGA,"弹出键盘");
KeyStatus = STATUS_SHOW;
// isShowKey = true;
}
}
});
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if (isShouldHideInput(v, ev) && KeyStatus != STATUS_HIDE) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
KeyStatus = STATUS_CLICK_OTHER;
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
return false;
}
}
return super.dispatchTouchEvent(ev);
}
// 必不可少,否则所有的组件都不会有TouchEvent了
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
public boolean isShouldHideInput(View v, MotionEvent event) {
if (v != null && (v instanceof EditText)) {
int[] leftTop = {0, 0};
//获取输入框当前的location位置
v.getLocationInWindow(leftTop);
int left = leftTop[0];
int top = leftTop[1];
int bottom = top + v.getHeight();
int right = left + v.getWidth();
if (event.getRawX() > left && event.getRawX() < right
&& event.getRawY() > top && event.getRawY() < bottom) {
// 点击的是输入框区域,保留点击EditText的事件
Toast.makeText(mContext,"是editext",Toast.LENGTH_SHORT).show();
Log.d(TGA,"是editext");
return false;
} else {
return true;
}
}
return false;
}
}
为了实现点击键盘外面的区域收起键盘,一般都是重写dispatchTouchEvent来截取点击事件,在这里判读你所点击的View是不是一个edittext的这里要注意这里获取点击事件的位置时,一定要用getRawX和 getRawY这样才能获取正确的位置。