天天看点

Android 软键盘工具类

作者:fishforest  原文章地址

public class SoftInputUtil {


    private int softInputHeight = 0;
    private boolean softInputHeightChanged = false;

    private boolean isNavigationBarShow = false;
    private int navigationHeight = 0;

    private View anyView;
    private ISoftInputChanged listener;
    private boolean isSoftInputShowing = false;

    public interface ISoftInputChanged {
        void onChanged(boolean isSoftInputShow, int softInputHeight, int viewOffset);
    }

    public void attachSoftInput(final View anyView, final ISoftInputChanged listener) {
        if (anyView == null || listener == null)
            return;

        //根View
        final View rootView = anyView.getRootView();
        if (rootView == null)
            return;

        navigationHeight = getNavigationBarHeight(anyView.getContext());

        //anyView为需要调整高度的View,理论上来说可以是任意的View
        this.anyView = anyView;
        this.listener = listener;

        rootView.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) {
                //对于Activity来说,该高度即为屏幕高度
                int rootHeight = rootView.getHeight();
                Rect rect = new Rect();
                //获取当前可见部分,默认可见部分是除了状态栏和导航栏剩下的部分
                rootView.getWindowVisibleDisplayFrame(rect);

                if (rootHeight - rect.bottom == navigationHeight) {
                    //如果可见部分底部与屏幕底部刚好相差导航栏的高度,则认为有导航栏
                    isNavigationBarShow = true;
                } else if (rootHeight - rect.bottom == 0) {
                    //如果可见部分底部与屏幕底部平齐,说明没有导航栏
                    isNavigationBarShow = false;
                }

                //cal softInput height
                boolean isSoftInputShow = false;
                int softInputHeight = 0;
                //如果有导航栏,则要去除导航栏的高度
                int mutableHeight = isNavigationBarShow == true ? navigationHeight : 0;
                if (rootHeight - mutableHeight > rect.bottom) {
                    //除去导航栏高度后,可见区域仍然小于屏幕高度,则说明键盘弹起了
                    isSoftInputShow = true;
                    //键盘高度
                    softInputHeight = rootHeight - mutableHeight - rect.bottom;
                    if (SoftInputUtils.this.softInputHeight != softInputHeight) {
                        softInputHeightChanged = true;
                        SoftInputUtils.this.softInputHeight = softInputHeight;
                    } else {
                        softInputHeightChanged = false;
                    }
                }

                //获取目标View的位置坐标
                int[] location = new int[2];
                anyView.getLocationOnScreen(location);

                //条件1减少不必要的回调,只关心前后发生变化的
                //条件2针对软键盘切换手写、拼音键等键盘高度发生变化
                if (isSoftInputShowing != isSoftInputShow || (isSoftInputShow && softInputHeightChanged)) {
                    if (listener != null) {
                        //第三个参数为该View需要调整的偏移量
                        //此处的坐标都是相对屏幕左上角(0,0)为基准的
                        listener.onChanged(isSoftInputShow, softInputHeight, location[1] + anyView.getHeight() - rect.bottom);
                    }

                    isSoftInputShowing = isSoftInputShow;
                }
            }
        });
    }


    //***************STATIC METHOD******************

    public static int getNavigationBarHeight(Context context) {
        if (context == null)
            return 0;
        Resources resources = context.getResources();
        int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
        int height = resources.getDimensionPixelSize(resourceId);
        return height;
    }

    public static void showSoftInput(View view) {
        if (view == null)
            return;
        InputMethodManager inputMethodManager = (InputMethodManager)view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (inputMethodManager != null) {
            inputMethodManager.showSoftInput(view, 0);
        }
    }

    public static void hideSoftInput(View view) {
        if (view == null)
            return;
        InputMethodManager inputMethodManager = (InputMethodManager)view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (inputMethodManager != null) {
            inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }
    }
}
           

使用方式如下:

在Activity里加如下代码:

private void attachView() {


    //editText2为需要调整的View
    editText2 = findViewById(R.id.et2);
    SoftInputUtil softInputUtil = new SoftInputUtil();
    softInputUtil.attachSoftInput(editText2, new SoftInputUtil.ISoftInputChanged() {
        @Override
        public void onChanged(boolean isSoftInputShow, int softInputHeight, int viewOffset) {
            if (isSoftInputShow) {
                editText2.setTranslationY(et2.getTranslationY() - viewOffset);
            } else {
                editText2.setTranslationY(0);
            }
        }
    });
}
           

并且将windowSoftInputMode 设置为SOFT_INPUT_ADJUST_RESIZE。

android:windowSoftInputMode="adjustResize|stateAlwaysHidden"