[轉(zhuǎn)]Android軟鍵盤監(jiān)聽高度變化,打開關(guān)閉,任意View跟隨軟鍵盤進(jìn)行平移

前言:

android上獲取對(duì)軟鍵盤的處理一直都是個(gè)頭疼的問(wèn)題,基本都是通過(guò)對(duì)view設(shè)置addOnGlobalLayoutListener來(lái)進(jìn)行監(jiān)聽,但這個(gè)監(jiān)聽有很多問(wèn)題,比如調(diào)用任意view的layout此函數(shù)就會(huì)進(jìn)行回調(diào),而且計(jì)算高度的時(shí)候經(jīng)常會(huì)因?yàn)橐恍顟B(tài)欄,導(dǎo)航欄的顯示造成軟鍵盤高度計(jì)算錯(cuò)誤的問(wèn)題。最終這個(gè)問(wèn)題在android 11上得到了解決,可以通過(guò)調(diào)用setWindowInsetsAnimationCallback設(shè)置對(duì)系統(tǒng)UI的顯示隱藏進(jìn)行監(jiān)聽。

實(shí)現(xiàn)效果:

導(dǎo)入依賴:

由于setWindowInsetsAnimationCallback方法在android 11上才出現(xiàn),對(duì)于低版本手機(jī)我們?cè)撊绾翁幚?,google對(duì)此進(jìn)行了兼容,我們需要在項(xiàng)目中添加androidX core的最新版,就可以調(diào)用向下兼容的api

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

創(chuàng)建callback:

首先我們創(chuàng)建類RootViewDeferringInsetsCallback繼承自WindowInsetAnimationCompat.Callback同時(shí)實(shí)現(xiàn)OnAppWindowInsetsListener。

onApplyWindowInsets(此方法屬于OnAppWindowInsetsListener)

在此方法中,我們獲取到實(shí)時(shí)變化的windowInsets,用來(lái)進(jìn)行可見性判斷和后續(xù)的分發(fā)

onPrepare(系統(tǒng)ui動(dòng)畫開始)

在此方法中,我們獲取到當(dāng)前正在進(jìn)行動(dòng)畫的類型,判斷是軟鍵盤的情況下設(shè)置deferredInsets為true并可以通過(guò)WindowInsets判斷軟鍵盤是否可見

onProgress(系統(tǒng)ui動(dòng)畫過(guò)程)

此處對(duì)軟鍵盤和系統(tǒng)bar進(jìn)行處理并獲取到實(shí)時(shí)高度

onEnd(系統(tǒng)ui動(dòng)畫結(jié)束)

在此方法中,我們對(duì)deferedInsets設(shè)置為false并對(duì)insets進(jìn)行分發(fā)

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<WindowInsetsAnimationCompat> runningAnimations) {
    if (deferredInsets) {
        //處理其他系統(tǒng)bar和軟鍵盤同時(shí)顯示情況高度計(jì)算問(wèn)題
        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);
        //獲取實(shí)時(shí)高度變化
        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());
        }
        //分發(fā)insets
       
        if (lastWindowInsets != null) {
            ViewCompat.dispatchApplyWindowInsets(view, lastWindowInsets);
        }
    }
}

}
設(shè)置監(jiān)聽

最后我們調(diào)用ViewCompat傳入任意view設(shè)置監(jiān)聽即可

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

除了對(duì)軟鍵盤的監(jiān)聽以外,我們還可以對(duì)任意系統(tǒng)ui進(jìn)行顯示和隱藏,或者進(jìn)行動(dòng)畫操作??梢酝ㄟ^(guò)WindowCompat.getInsetsController()方法拿到view的insets控制器。有很多非常方便的方法,感興趣的小伙伴可以進(jìn)行探究。

為了方便大家,我對(duì)軟鍵盤的監(jiān)聽進(jìn)行了封裝并上傳了git,此依賴可以在任意地方進(jìn)行軟鍵盤高度的監(jiān)聽,并且可以設(shè)置任意view進(jìn)行跟隨平移,大家可以直接添加依賴進(jìn)行使用~

https://github.com/rockscy/uicontroll

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容