Android监听系统输入法键盘弹出显示与隐藏事件
有时候需要监听Android系统输入法的弹出显示事件,比如:微信聊天时,不管你当前在聊天中的什么位置(上滑查看消息历史),每当你点击输入框时,都会自动帮你聚集到最新的聊天记录。
而android系统没有提供对应的API来监听输入法的显示与隐藏,那就需要我们自己来实现了。
我目前发现有2种方式可以实现。实现原理:通过监听布局的高度变化来间接监听输入法的弹出事件
- 方式一
通过父布局的onLayout回调高度的改变来判断输入法的显示与隐藏
上代码!
public class MyMeasureLinearLayout extends LinearLayout {
public static final String TAG = "MeasureLinearLayout";
public static final boolean DEBUG = true;
private FragmentSizeObserver mObserver;
private int initBottom = -1;
private int initLeft = -1;
public MyMeasureLinearLayout(Context context){
this(context, null);
}
public MyMeasureLinearLayout(Context context, AttributeSet attrs){
this(context, attrs, 0);
}
public MyMeasureLinearLayout(Context context, AttributeSet attrs,
int defStyleAttr){
super(context, attrs, defStyleAttr);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
super.onLayout(changed, l, t, r, b);
Log.d(TAG, " changed "+changed +" b "+b);
if(initBottom == -1 || initLeft == -1){
initBottom = b;
initLeft = l;
return;
}
if(changed){
Log.d(TAG, " height "+b +" width "+r
+" initBottom "+initBottom+" initLeft "+initLeft);
int height = b - initBottom; //高度变化值(弹出输入法,布局变小,则为负值)
int width = r - initLeft; // 当前屏幕宽度(对应输入法而言无影响)
onInputSizeChanged(width, height);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
private void onInputSizeChanged(int widthDiff,int heightDiff) {
if(mObserver != null){
mObserver.onFragmentSizeChanged(widthDiff, heightDiff);
}
}
public void registFragmentSizeObserver(FragmentSizeObserver observer) {
mObserver = observer;
}
public interface FragmentSizeObserver{
public void onFragmentSizeChanged(int wdiff,int hdiff);
}
}
原理分析:
自定义MyMeasureLinearLayout ,继承自LinearLayout,以该布局作为包含EditText View在内的父布局容器,当EditText获取焦点时,系统输入法弹出,则该父布局整体被上移了,下面留出空间来显示输入法,所以可以根据布局被移动前后的bottom值变化来计算出高度的差值。FragmentSizeObserver接口中的onFragmentSizeChanged方法表示高度发生变化时的回调,可以实现该方法来做输入法弹出与隐藏的逻辑。
代码参考:
实现
public void onFragmentSizeChanged(int wdiff, int hdiff) {
if (DEBUG)
Log.d(TAG, "onFragmentSizeChanged wdiff " + wdiff + " hdiff "
+ hdiff);
// doFragmentSizeChanged(wdiff, hdiff);
if(hdiff < -200){ // show soft input
// 处理输入法弹出事件
}
else if(hdiff == 0){ // hide soft input
// 处理输入法隐藏事件
if(null != mMessageRoot){
Log.d(TAG, "--keybord hide soft input--add messageRootListener ");
//mMessageRoot.getViewTreeObserver().addOnGlobalLayoutListener(messageRootListener);
}
}
}
- 方式二
可以不用实现自定义的布局,只需要用系统原生的布局如LinearLayout或RelativeLayout,获取根布局的实例,设置监听OnGlobalLayoutListener,通过根布局高度变化大小来判断输入法的弹出。
原理和方式一类似。注意一定要是在根布局上监听。
代码参考
...
mMessageRoot = (RelativeLayout) root.findViewById(R.id.message_root);
if(null != mMessageRoot){
mMessageRoot.getViewTreeObserver().addOnGlobalLayoutListener(messageRootListener);
}
....
OnGlobalLayoutListener messageRootListener = new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightDiff = mMessageRoot.getRootView().getHeight() - mMessageRoot.getHeight();
if(heightDiff > 250){ // 700c (113, 473); 880 (146, 728); 850 (219, 1044)
// keybord has show
if(null != mListView){
mListView.setSelectionFromTop(mDataList.size() - 1, -30);
mMessageRoot.getViewTreeObserver().removeOnGlobalLayoutListener(messageRootListener);// 执行完输入法弹出逻辑后,应及时取消监听
Log.d(TAG, "--keybord has show we set the select index :"+(mDataList.size() -1));
}
}
Log.d(TAG, "--messageRootListener--heightDiff:"+heightDiff);
}
};
....
public void onFragmentSizeChanged(int wdiff, int hdiff) {
if(hdiff == 0){ // hide soft input
if(null != mMessageRoot){
Log.d(TAG, "--keybord hide soft input--add messageRootListener ");
//输入法隐藏后,继续添加监听
mMessageRoot.getViewTreeObserver().addOnGlobalLayoutListener(messageRootListener);
}
}
}
总结:通过布局的高度变化来间接实现监听输入法的弹出事件,布局高度的变化监听有不同的方法,我列出的方法仅供参考,借此抛砖引玉,欢迎大家评论留言。