End

软键盘 显示隐藏 测量高度

本文地址


目录

软键盘相关问题

我们在开发中经常会遇到软键盘遮挡住了输入框,而直接把输入框往上顶adjustResize这种方法过于暴力影响美观,我们希望键盘弹出时动态的去改变布局。这时候,便用到了监听键盘弹起事件的功能。

可能大家都会潜意识觉得:Android中没有可以复写的方法么?或者说,没有什么listener可以让我们使用么?

抱歉,真的没有,我们潜意识都是以为系统会提供,其实系统提供的是InputMethodManager,让我们控制键盘的弹出和隐藏,而不是键盘弹出和隐藏触发事件。

Android系统并没有给我们提供监听键盘弹出的方法,同样,Android系统也没有给我们提供获取软键盘的高度的方法,我们只能自己监听view的高度变化来间接判断键盘是不是弹出了,并通过计算获取软键盘的高度。

目前通用的方法是,由于键盘弹起与隐藏,会使得layout的布局发生变化,通过布局的大小变化触发的事件实现键盘事件的触发。

设置 OnLayoutChangeListener - 推荐

不要忘了设置键盘

android:windowSoftInputMode="stateAlwaysHidden|adjustResize"

使用

public class MainActivity extends Activity {
    
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.edit);

        int scrollHeight = getWindowManager().getDefaultDisplay().getHeight() / 4;
        findViewById(android.R.id.content).addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
            if (oldBottom != 0 && bottom != 0) {
                int softInputHeight = oldBottom - bottom;//这个就是键盘高度
                Log.i("bqt", "【键盘高度】" + Math.abs(softInputHeight));
                
                if (softInputHeight > scrollHeight) {
                    Toast.makeText(MainActivity.this, "键盘弹起", Toast.LENGTH_SHORT).show();
                } else if (Math.abs(softInputHeight) > scrollHeight) {
                    Toast.makeText(MainActivity.this, "键盘落下", Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}

设置 OnGlobalLayoutListener - 推荐

不要忘了设置键盘

android:windowSoftInputMode="stateAlwaysHidden|adjustResize"

使用

public class MainActivity extends Activity {
    private int keyboardHeight;
    
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.edit);

        new KeyboardChangeListener(this).setKeyBoardListener((isShow, keyboardCurrentHeight) -> {
            Log.i("bqt", "【当前键盘的高度】" + keyboardCurrentHeight);//注意,这里返回的直接是键盘的高度,键盘隐藏时高度为0
            if (isShow) {
                this.keyboardHeight = keyboardCurrentHeight;
                Log.i("bqt", "【键盘的高度】" + keyboardHeight);
                Toast.makeText(MainActivity.this, "键盘弹起", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(MainActivity.this, "键盘隐藏", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

KeyboardChangeListener

public class KeyboardChangeListener implements ViewTreeObserver.OnGlobalLayoutListener {
    private static final String TAG = "bqt";
    private View mContentView;
    private int mOriginHeight;
    private int mPreHeight;
    private KeyBoardListener mKeyBoardListen;
    
    public interface KeyBoardListener {
        /**
         * call back
         *
         * @param isShow         true is show else hidden
         * @param keyboardHeight keyboard height
         */
        void onKeyboardChange(boolean isShow, int keyboardHeight);
    }
    
    public void setKeyBoardListener(KeyBoardListener keyBoardListen) {
        this.mKeyBoardListen = keyBoardListen;
    }
    
    public KeyboardChangeListener(Activity contextObj) {
        if (contextObj == null) {
            Log.i(TAG, "contextObj is null");
            return;
        }
        mContentView = findContentView(contextObj);
        if (mContentView != null) {
            addContentTreeObserver();
        }
    }
    
    private View findContentView(Activity contextObj) {
        return contextObj.findViewById(android.R.id.content);
    }
    
    private void addContentTreeObserver() {
        mContentView.getViewTreeObserver().addOnGlobalLayoutListener(this);
    }
    
    @Override
    public void onGlobalLayout() {
        int currHeight = mContentView.getHeight();
        if (currHeight == 0) {
            Log.i(TAG, "currHeight is 0");
            return;
        }
        boolean hasChange = false;
        if (mPreHeight == 0) {
            mPreHeight = currHeight;
            mOriginHeight = currHeight;
        } else {
            if (mPreHeight != currHeight) {
                hasChange = true;
                mPreHeight = currHeight;
            } else {
                hasChange = false;
            }
        }
        if (hasChange) {
            boolean isShow;
            int keyboardHeight = 0;
            if (mOriginHeight == currHeight) {
                //hidden
                isShow = false;
            } else {
                //show
                keyboardHeight = mOriginHeight - currHeight;
                isShow = true;
            }
            
            if (mKeyBoardListen != null) {
                mKeyBoardListen.onKeyboardChange(isShow, keyboardHeight);
            }
        }
    }
    
    @SuppressLint("ObsoleteSdkInt")
    public void destroy() {
        if (mContentView != null) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                mContentView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }
        }
    }
}

重写 onSizeChanged - 麻烦,不推荐

不要忘了设置键盘

android:windowSoftInputMode="stateAlwaysHidden|adjustResize"

使用

public class MainActivity extends Activity {
    
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.edit);
        
        AdjustSizeRelativeLayout layout = findViewById(R.id.rl_root);
        layout.setSoftKeyBoardListener(new AdjustSizeRelativeLayout.SoftkeyBoardListener() {
            @Override
            public void keyBoardVisable(int move) {
                Toast.makeText(MainActivity.this, "键盘弹起,高度:" + move, Toast.LENGTH_SHORT).show();
            }
            
            @Override
            public void keyBoardInvisable(int move) {
                Toast.makeText(MainActivity.this, "键盘隐藏,高度:" + move, Toast.LENGTH_SHORT).show();
            }
        });
    }
}

布局

<?xml version="1.0" encoding="utf-8"?>
<com.bqt.test.AdjustSizeRelativeLayout 
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/rl_root"
     android:layout_width="match_parent"
     android:layout_height="match_parent">

    <EditText
        android:layout_width="match_parent"
        android:layout_height="44dp"
        android:layout_alignParentBottom="true"
        android:hint="输入交易密码"
        android:inputType="text"
        android:paddingLeft="5dp"/>

</com.bqt.test.AdjustSizeRelativeLayout>

自定义的ViewGroup

public class AdjustSizeRelativeLayout extends RelativeLayout {
    public AdjustSizeRelativeLayout(Context context) {
        super(context);
    }
    
    public AdjustSizeRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    
    public AdjustSizeRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    private static final int CHANGE_SIZE = 200;
    
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        Log.i("bqt", "【onSizeChanged】" + w + " " + h + " " + oldw + " " + oldh);
        if (oldw == 0 || oldh == 0) return;

        if (boardListener != null) {
            if (h - oldh < -CHANGE_SIZE) {
                Log.i("bqt", "键盘弹出" + "change" + w + " " + h + " " + oldw + " " + oldh);
                boardListener.keyBoardVisable(Math.abs(h - oldh));
            }
            if (h - oldh > CHANGE_SIZE) {
                Log.i("bqt", "键盘结束" + "change" + w + " " + h + " " + oldw + " " + oldh);
                boardListener.keyBoardInvisable(Math.abs(h - oldh));
            }
        }
    }
    
    public interface SoftkeyBoardListener {
        public void keyBoardVisable(int move);
        
        public void keyBoardInvisable(int move);
    }
    
    private SoftkeyBoardListener boardListener;
    
    public void setSoftKeyBoardListener(SoftkeyBoardListener boardListener) {
        this.boardListener = boardListener;
    }
}

2018-5-21

posted @ 2018-05-21 10:54  白乾涛  阅读(571)  评论(0编辑  收藏  举报