Android

【Android】键盘挡住输入框

2019-08-06  本文已影响0人  Sraindy

问题描述:

根据(android全屏/沉浸式状态栏下,各种键盘挡住输入框解决办法)[https://blog.csdn.net/smileiam/article/details/69055963]中的详解方法五

思路:

输入法没显示时,手机界面分为两块即状态栏和内容区域。


image.png

输入法显示时,手机界面分为三块即状态栏,内容区域,输入法显示区域


image.png

原理:

1、获取Activity的setContentView里的View
所有的Activity都是DecorView,它就是一个FrameLayout控件,该控件id是系统写死叫R.id.content,就是我们setContentView时,把相应的View放在此FrameLayout控件里。

FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content)
所以content.getChildAt(0)获取到的mChildOfContent,也就是我们用setContentView放进去的View。

2、给Activity的xml布局View设置一个监听视图树布局发生改变

  mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            //4、软键盘弹起会使GlobalLayout发生变化
            public void onGlobalLayout() {

              }
});
View.getViewTreeObserver()可以获取一个ViewTreeObserver对象——它是一个观察者,用以监听当前View树所发生的变化。
这里所注册的addOnGlobalLayoutListener,就是会在当前的View树的全局布局(GlobalLayout)发生变化、或者其中的View可视状态有变化时,进行通知回调。『软键盘弹出/隐 』都能监听到。 

3、获取内容区域(即当前窗口可视区域)

 private int computeUsableHeight() {
        Rect r = new Rect();
        /**
         * 一个窗口中通常都会有多个View,getWindowVisibleDisplayFrame()方法的返回结果和该窗口中选取的View并没有关系。
         * 在某个时刻,使用当前窗口中的任意View执行getWindowVisibleDisplayFrame()返回的结果都是一样的。
         */
        //获取当前窗口可视区域大小的
        mChildOfContent.getWindowVisibleDisplayFrame(r);
        Log.i("zss", "----r.bottom:" + r.bottom + "  ; r.top:" + r.top);
        // 全屏模式下:直接返回r.bottom,r.top其实是状态栏的高度
        return (r.bottom - r.top);
    }
r.bottom - r.top:表示当前窗口可视区域的高度

4、获取手机屏幕的高度

  int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();

5、输入法的高度

//输入法的高度 = 手机屏幕的高度 - 当前窗口.bottom
 int heightDifference = usableHeightSansKeyboard - usableHeightNow;//(含义状态栏的高度)

注意:如果既使用了沉浸式状态栏,又加了fitSystetemWindow=true属性,就需要在AndroidMainfest.xml注册Activity的地方添加上以下属性。因为你两种都用,系统不知道用哪种了。fitSystetemWindow已经有resize屏幕的作用。

  android:windowSoftInputMode="stateHidden|adjustPan"

测试代码如下

(1)布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#ff0000"
        android:orientation="vertical"></LinearLayout>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:orientation="vertical">

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="1" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="2" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="3" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="4" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="5" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="6" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="7" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="8" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="9" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="10" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="11" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="12" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="13" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="14" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="15" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="16" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="17" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="18" />

            <EditText
                android:layout_width="match_parent"
                android:layout_height="48dp"
                android:hint="19" />
        </LinearLayout>
    </ScrollView>
</LinearLayout>

(2)工具类

package demo.com.keyboarddemo;

import android.app.Activity;
import android.graphics.Rect;
import android.os.Build;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;

public class SoftHideKeyBoardUtil {
    public static void assistActivity(Activity activity) {
        new SoftHideKeyBoardUtil(activity);
    }

    private View mChildOfContent;
    private int usableHeightPrevious;
    private FrameLayout.LayoutParams frameLayoutParams;
    //为适应华为小米等手机键盘上方出现黑条或不适配
    private int contentHeight;//获取setContentView本来view的高度
    private boolean isfirst = true;//只用获取一次
    private int statusBarHeight;//状态栏高度

    private SoftHideKeyBoardUtil(Activity activity) {
        //1、找到Activity的最外层布局控件,它其实是一个DecorView,它所用的控件就是FrameLayout
        FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
        //2、获取到setContentView放进去的View
        mChildOfContent = content.getChildAt(0);
        //3、给Activity的xml布局设置View树监听,当布局有变化,如键盘弹出或收起时,都会回调此监听
        mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            //4、软键盘弹起会使GlobalLayout发生变化
            public void onGlobalLayout() {
                if (isfirst) {
                    contentHeight = mChildOfContent.getHeight();//兼容华为等机型
                    isfirst = false;
                }
                //5、当前布局发生变化时,对Activity的xml布局进行重绘
                possiblyResizeChildOfContent();
            }
        });
        //6、获取到Activity的xml布局的放置参数
        frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();
    }

    // 获取界面可用高度,如果软键盘弹起后,Activity的xml布局可用高度需要减去键盘高度
    private void possiblyResizeChildOfContent() {
        //1、获取当前界面可用高度,键盘弹起后,当前界面可用布局会减少键盘的高度
        int usableHeightNow = computeUsableHeight();

        //2、如果当前可用高度和原始值不一样
        if (usableHeightNow != usableHeightPrevious) {
            //3、获取Activity中xml中布局在当前界面显示的高度
            int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();
            Log.i("zss", "------ 获取Activity中xml中布局在当前界面显示的高度:" + usableHeightSansKeyboard);
            //4、Activity中xml布局的高度-当前可用高度
            int heightDifference = usableHeightSansKeyboard - usableHeightNow;
            Log.i("zss", "------ Activity中xml布局的高度-当前可用高度:" + heightDifference + "  状态栏:" + statusBarHeight);

            //5、高度差大于屏幕1/4时,说明键盘弹出
            if (heightDifference > (usableHeightSansKeyboard / 4)) {
                // 6、键盘弹出了,Activity的xml布局高度应当减去键盘高度
                frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;

            } else {
                frameLayoutParams.height = contentHeight;
            }
            //7、 重绘Activity的xml布局
            mChildOfContent.requestLayout();
            usableHeightPrevious = usableHeightNow;
        }
    }

    private int computeUsableHeight() {
        Rect r = new Rect();
        /**
         * 一个窗口中通常都会有多个View,getWindowVisibleDisplayFrame()方法的返回结果和该窗口中选取的View并没有关系。
         * 在某个时刻,使用当前窗口中的任意View执行getWindowVisibleDisplayFrame()返回的结果都是一样的。
         */
        //获取当前窗口可视区域大小的
        mChildOfContent.getWindowVisibleDisplayFrame(r);
        Log.i("zss", "----r.bottom:" + r.bottom + "  ; r.top:" + r.top);
        // 全屏模式下:直接返回r.bottom,r.top其实是状态栏的高度
//        return (r.bottom - r.top);
        return r.bottom;
    }
}

(3)使用

package demo.com.keyboarddemo;

import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class EditViewTestActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_edit_view_test);
        SoftHideKeyBoardUtil.assistActivity(this);
    }
}

上一篇下一篇

猜你喜欢

热点阅读