[转]Android软键盘监听高度变化,打开关闭,任意View跟随软键盘进行平移

前言:

android上获取对软键盘的处理一直都是个头疼的问题,基本都是通过对view设置addOnGlobalLayoutListener来进行监听,但这个监听有很多问题,比如调用任意view的layout此函数就会进行回调,而且计算高度的时候经常会因为一些状态栏,导航栏的显示造成软键盘高度计算错误的问题。最终这个问题在android 11上得到了解决,可以通过调用setWindowInsetsAnimationCallback设置对系统UI的显示隐藏进行监听。

实现效果:

导入依赖:

由于setWindowInsetsAnimationCallback方法在android 11上才出现,对于低版本手机我们该如何处理,google对此进行了兼容,我们需要在项目中添加androidX core的最新版,就可以调用向下兼容的api

implementation "androidx.core:core:1.5.0-beta02"

创建callback:

首先我们创建类RootViewDeferringInsetsCallback继承自WindowInsetAnimationCompat.Callback同时实现OnAppWindowInsetsListener。

onApplyWindowInsets(此方法属于OnAppWindowInsetsListener)

在此方法中,我们获取到实时变化的windowInsets,用来进行可见性判断和后续的分发

onPrepare(系统ui动画开始)

在此方法中,我们获取到当前正在进行动画的类型,判断是软键盘的情况下设置deferredInsets为true并可以通过WindowInsets判断软键盘是否可见

onProgress(系统ui动画过程)

此处对软键盘和系统bar进行处理并获取到实时高度

onEnd(系统ui动画结束)

在此方法中,我们对deferedInsets设置为false并对insets进行分发

public class RootViewDeferringInsetsCallback extends WindowInsetsAnimationCompat.Callback implements OnApplyWindowInsetsListener {
private final KeyboardListener keyboardListener;

public RootViewDeferringInsetsCallback(int dispatchMode, KeyboardListener keyboardListener) {
    super(dispatchMode);
    this.keyboardListener = keyboardListener;
}

private View view;
private WindowInsetsCompat lastWindowInsets;

private boolean deferredInsets = false;


@Override
public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
    view = v;
    lastWindowInsets = insets;
    return WindowInsetsCompat.CONSUMED;
}

@Override
public void onPrepare(@NonNull WindowInsetsAnimationCompat animation) {
    if ((animation.getTypeMask() & WindowInsetsCompat.Type.ime()) != 0) {
        deferredInsets = true;
        boolean visible = false;
        if(lastWindowInsets!=null) {
            visible =  lastWindowInsets.isVisible(WindowInsetsCompat.Type.ime());
        }
        keyboardListener.onKeyBoardAnimStart(visible);
    }
}

@NonNull
@Override
public WindowInsetsCompat onProgress(@NonNull WindowInsetsCompat insets, @NonNull List runningAnimations) {
    if (deferredInsets) {
        //处理其他系统bar和软键盘同时显示情况高度计算问题
        Insets typesInset = insets.getInsets(WindowInsetsCompat.Type.ime());

        Insets otherInset = insets.getInsets(WindowInsetsCompat.Type.systemBars());


        Insets subtract = Insets.subtract(typesInset, otherInset);
        Insets diff = Insets.max(subtract, Insets.NONE);
        //获取实时高度变化
        int height = diff.bottom;
    }
    return insets;
}

@Override
public void onEnd(@NonNull WindowInsetsAnimationCompat animation) {
    if (deferredInsets && (animation.getTypeMask() & WindowInsetsCompat.Type.ime()) != 0) {
        deferredInsets = false;
        boolean visible = false;
       
        //软键盘是否显示
        if(lastWindowInsets!=null) {
            visible =  lastWindowInsets.isVisible(WindowInsetsCompat.Type.ime());
        }
        //分发insets
       
        if (lastWindowInsets != null) {
            ViewCompat.dispatchApplyWindowInsets(view, lastWindowInsets);
        }
    }
}

}
设置监听

最后我们调用ViewCompat传入任意view设置监听即可

RootViewDeferringInsetsCallback rootViewInsetsCallback = new RootViewDeferringInsetsCallback(WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE, keyBoardListener);
ViewCompat.setOnApplyWindowInsetsListener(view, rootViewInsetsCallback);
ViewCompat.setWindowInsetsAnimationCallback(view, rootViewInsetsCallback);
其他

除了对软键盘的监听以外,我们还可以对任意系统ui进行显示和隐藏,或者进行动画操作。可以通过WindowCompat.getInsetsController()方法拿到view的insets控制器。有很多非常方便的方法,感兴趣的小伙伴可以进行探究。

为了方便大家,我对软键盘的监听进行了封装并上传了git,此依赖可以在任意地方进行软键盘高度的监听,并且可以设置任意view进行跟随平移,大家可以直接添加依赖进行使用~

https://github.com/rockscy/uicontroll

你可能感兴趣的:([转]Android软键盘监听高度变化,打开关闭,任意View跟随软键盘进行平移)