目录

  • 一、Android 键盘监听
  • 三、NestedScrollView+ android:windowSoftInputMode="stateHidden|adjustResize"


一、Android 键盘监听

windowSoftInputMode属性

(1)软键盘的状态——隐藏或显示。
(2)活动的主窗口调整:是否减少活动主窗口大小以便腾出空间放软键盘或是否当活动窗口的部分被软键盘覆盖时它的内容的当前焦点是可见的。

这个属性的可选属性值有以下几个:

设置规则:

该属性的设置必须是下面列表中的一个值,或一个“state…”值加一个“adjust…”值的组合。 在任一组设置多个值,各个值之间用|分开。 state开头: -------------------------------------------------------------------------------------------- "stateUnspecified": 软键盘的状态(隐藏或可见)没有被指定。系统将选择一个合适的状态或依赖于主题的设置。这个是软件盘行为的默认设置。 "stateUnchanged":软键盘被保持上次的状态。 "stateHidden":当用户选择该Activity时,软键盘被隐藏。 "stateAlwaysHidden": 软键盘总是被隐藏的。 "stateVisible": 软键盘是可见的。 "stateAlwaysVisible": 当用户选择这个Activity时,软键盘是可见的。 adjust开头: ---------------------------------------------------------------------------------------------- "adjustUnspecified":默认设置,通常由系统自行决定是隐藏还是显示:决定因素在于内容是否可以滚动。 "adjustResize":(压缩,上顶)当软键盘弹出时,对主窗口调整屏幕的大小以便留出软键盘的空间。 "adjustPan":(平移)始终保持输入框为可见:当输入框不会被遮挡时,该模式不会对布局进行调整,而当输 入框将要被遮挡时,窗口就会进行平移(这里:输入框以下的布局内容依然会被遮挡)。当前窗口的内容会自动移动,从而保证当前焦点不被键盘覆盖 以及用户总能看到输入内容的部分。此模式下,用户只有关闭软键盘才能与被覆盖内容的交互操作。

二、监听工具

public class SoftKeyBoardListener {
    private View rootView;//activity的根视图
    int rootViewVisibleHeight;//纪录根视图的显示高度
    private OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener;

    public SoftKeyBoardListener(Activity activity) {
        //获取activity的根视图
        rootView = activity.getWindow().getDecorView();

        //监听视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变
        rootView.getViewTreeObserver().addOnGlobalLayoutListener(() -> {
            //获取当前根视图在屏幕上显示的大小
            Rect r = new Rect();
            rootView.getWindowVisibleDisplayFrame(r);

            int visibleHeight = r.height();
            System.out.println("showInputDialog visibleHeight=" + visibleHeight);
            if (rootViewVisibleHeight == 0) {
                rootViewVisibleHeight = visibleHeight;
                return;
            }

            //根视图显示高度没有变化,可以看作软键盘显示/隐藏状态没有改变
            if (rootViewVisibleHeight == visibleHeight) {
                return;
            }

            //根视图显示高度变小超过200,可以看作软键盘显示了
            if (rootViewVisibleHeight - visibleHeight > 200) {
                if (onSoftKeyBoardChangeListener != null) {
                    onSoftKeyBoardChangeListener.keyBoardShow(rootViewVisibleHeight - visibleHeight);
                }
                rootViewVisibleHeight = visibleHeight;
                return;
            }

            //根视图显示高度变大超过200,可以看作软键盘隐藏了
            if (visibleHeight - rootViewVisibleHeight > 200) {
                if (onSoftKeyBoardChangeListener != null) {
                    onSoftKeyBoardChangeListener.keyBoardHide(visibleHeight - rootViewVisibleHeight);
                }
                rootViewVisibleHeight = visibleHeight;
                return;
            }

        });
    }

    private void setOnSoftKeyBoardChangeListener(OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) {
        this.onSoftKeyBoardChangeListener = onSoftKeyBoardChangeListener;
    }

    public interface OnSoftKeyBoardChangeListener {
        void keyBoardShow(int height);

        void keyBoardHide(int height);
    }

    public static void setListener(Activity activity, OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) {
        SoftKeyBoardListener softKeyBoardListener = new SoftKeyBoardListener(activity);
        softKeyBoardListener.setOnSoftKeyBoardChangeListener(onSoftKeyBoardChangeListener);
    }

}

三、NestedScrollView+ android:windowSoftInputMode=“stateHidden|adjustResize”

处理方案:
在NestedScrollView 中最底下设置一个空布局并设置高度

<RelativeLayout
                android:id="@+id/input_placeholder_layout"
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:visibility="gone" />

执行方案:

private void initStickyScrollView() {
        scrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
            @Override
            public void onScrollChange(NestedScrollView nestedScrollView, int i, int i1, int i2, int i3) {
                //判断某个控件是否可见
                /*Rect scrollBounds = new Rect();
                stickyScrollView.getHitRect(scrollBounds);
                if (menuLayout.getLocalVisibleRect(scrollBounds)) {//可见
                    LogUtils.e(TAG, "showAddrDialog onScrollChange:  第3个可见");
                } else {//完全不可见
                    LogUtils.e(TAG, "showAddrDialog onScrollChange:  第3个不可见");
                }*/
//                //判断某个控件是否滚到顶部
                if (i1 == getStickyScrollY()) {
                    LogUtils.i(TAG, "showAddrDialog onScrollChange: ------到位置了-------");
                } else {
                    LogUtils.i(TAG, "showAddrDialog onScrollChange: ------没到-------" + isStickyVisibleRect);
                    //保证最终能滑动到指定位置
                    if (isStickyVisibleRect) {
                        isStickyVisibleRect = false;
                        scrollView.scrollTo(0, inputPlaceholderLayout.getTop());
                    }
                }
            }
        });

		//监听输入法键盘监听
        SoftKeyBoardListener.setListener(this, new SoftKeyBoardListener.OnSoftKeyBoardChangeListener() {
            @Override
            public void keyBoardShow(int height) {
                LogUtils.d("showInputDialog  keyBoardShow " + edt_desc.isFocused());
                if (edt_desc.isFocused()) {//执行滑动
                    setStickyScrollY();
                }
            }

            @Override
            public void keyBoardHide(int height) {
                LogUtils.d("showInputDialog  keyBoardHide");
                if (!isStickyVisibleRect) {//隐藏底部布局占位,将原有布局高度顶上去
                    inputPlaceholderLayout.setVisibility(View.GONE);
                }
            }
        });

		// 第一次进来点击执行,之后点击将不会被执行,所以需要监听点击事件
        edt_desc.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                LogUtils.d("showInputDialog  onFocusChange=" + hasFocus);
                if (hasFocus) {//显示底部布局占位,将原有布局高度顶上去
                    inputPlaceholderLayout.setVisibility(View.VISIBLE);
                }
            }
        });
        //点击事件
        edt_desc.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                LogUtils.d("showInputDialog  onClick");
                inputPlaceholderLayout.setVisibility(View.VISIBLE);
            }
        });
    }

	//获得需要滑动的位置,这里是因EditTxet在最底下,所以获取inputPlaceholderLayout底部位置
    private int getStickyScrollY() {
        return inputPlaceholderLayout.getBottom();
    }

    private boolean isStickyVisibleRect = false;
	
	//执行NestedScrollView 滑动
    private void setStickyScrollY() {
        LogUtils.d("showInputDialog  setStickyScrollY");
        isStickyVisibleRect = true;
        scrollView.scrollTo(0, getStickyScrollY());
    }