android 輸入法顯示隱藏監聽

先看使用代碼,非常簡單,就是弄一個回調處理就行,其他的不用關心

        SoftKeyBoardListener.setListener(this,object :SoftKeyBoardListener.OnSoftKeyBoardChangeListener{
            override fun keyBoardShow(height: Int) {//height是鍵盤的高度
                
            }

            override fun keyBoardHide() {
                
            }
        })

工具類如下

import android.app.Activity;
import android.arch.lifecycle.GenericLifecycleObserver;
import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleOwner;
import android.content.Context;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;

public class SoftKeyBoardListener {
    public interface OnSoftKeyBoardChangeListener {
        void keyBoardShow(int height);

        void keyBoardHide();
    }

    private View rootView;//activity的根視圖
    private int screenBottom;//紀錄根視圖的顯示高度
    private OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener;
    boolean isShow = false;//軟鍵盤是否顯示
    private ViewTreeObserver.OnGlobalLayoutListener listener;

    private SoftKeyBoardListener(Activity activity) {
        int state = WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE & activity.getWindow().getAttributes().softInputMode;
        switch (state) {
            case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE:
            case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
                isShow = true;
                break;
        }
        //獲取activity的根視圖
        rootView = activity.getWindow().getDecorView();
        screenBottom = activity.getWindowManager().getDefaultDisplay().getHeight();
        //監聽視圖樹中全局佈局發生改變或者視圖樹中的某個視圖的可視狀態發生改變
        listener = new ViewTreeObserver.OnGlobalLayoutListener() {

            @Override

            public void onGlobalLayout() {

                //獲取當前根視圖在屏幕上顯示的大小
                Rect r = new Rect();

                rootView.getWindowVisibleDisplayFrame(r);

                System.out.println("rect============" + isShow + "===" + r.toShortString() + "===" + screenBottom);
                if (!isShow && screenBottom > r.bottom) {
                    isShow = true;
                    if (onSoftKeyBoardChangeListener != null) {
                        onSoftKeyBoardChangeListener.keyBoardShow(screenBottom - r.bottom);
                    }
                    return;
                }

                if (isShow && r.bottom >= screenBottom) {
                    isShow = false;
                    if (onSoftKeyBoardChangeListener != null) {
                        onSoftKeyBoardChangeListener.keyBoardHide();
                    }
                    return;
                }

            }

        };
        rootView.getViewTreeObserver().addOnGlobalLayoutListener(listener);
        addLifeObServer(activity);
    }

    private void setOnSoftKeyBoardChangeListener(OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) {

        this.onSoftKeyBoardChangeListener = onSoftKeyBoardChangeListener;

    }

    public static void setListener(Activity activity, OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) {

        SoftKeyBoardListener softKeyBoardListener = new SoftKeyBoardListener(activity);

        softKeyBoardListener.setOnSoftKeyBoardChangeListener(onSoftKeyBoardChangeListener);

    }

    public void addLifeObServer(Activity activity) {
        if (activity instanceof LifecycleOwner) {
            LifecycleOwner owner = (LifecycleOwner) activity;
            owner.getLifecycle().addObserver(new GenericLifecycleObserver() {
                @Override
                public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
                    if (event == Lifecycle.Event.ON_DESTROY) {
                        if (rootView != null)
                            rootView.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
                    }
                }
            });
        }
    }


    public static void closeKeybord(EditText mEditText, Context mContext) {

        InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);

        imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);

        mEditText.setFocusable(false);

    }
}

工具類簡單說明

核心方法就是rootView.getWindowVisibleDisplayFrame(r)
獲取可見的view的佈局範圍,然後根據屏幕計算出軟鍵盤的高度
isShow這個值的作用,軟鍵盤彈出以後,比如兩個輸入框,一個是文本,一個是數字,2個切換的時候軟鍵盤高度是會發生變化的,可這時候不需要回調鍵盤是否顯示的,所以顯示隱藏的回調不會多次執行,另外也能處理用戶如果默認軟鍵盤要求彈出的情況。

輸入法的模式問題

先看下輸入法支持的模式,如下,其實可以分爲兩類,一類是state,一類是adjust

@IntDef(flag = true, value = {
                SOFT_INPUT_STATE_UNSPECIFIED,//0
                SOFT_INPUT_STATE_UNCHANGED,//1
                SOFT_INPUT_STATE_HIDDEN,//2
                SOFT_INPUT_STATE_ALWAYS_HIDDEN,//3
                SOFT_INPUT_STATE_VISIBLE,//4
                SOFT_INPUT_STATE_ALWAYS_VISIBLE,//5
                SOFT_INPUT_ADJUST_UNSPECIFIED,//0x00
                SOFT_INPUT_ADJUST_RESIZE,//0x10
                SOFT_INPUT_ADJUST_PAN,//0x20
                SOFT_INPUT_ADJUST_NOTHING,//0x30
                SOFT_INPUT_IS_FORWARD_NAVIGATION,//0x100
        })

state從0到5,而adjust是十六進制的十位從0到3.這樣的目的,到時候通過一個mask可以取出state和adjust
比如 android:windowSoftInputMode="stateVisible|adjustResize"
拿到的softinputmode=4+16也就是20
這裏有2個mask
public static final int SOFT_INPUT_MASK_STATE = 0x0f;
public static final int SOFT_INPUT_MASK_ADJUST = 0xf0;

int state=WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE&mode;
進行與操作以後,高位就沒了,就剩下低位了,也就剩下個4了。
同理int adjust=WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST&mode;
低位就沒了,就剩下個十六進制的高位1了,也就是0x10,也就是拿到了adjust爲16

這種mask在MotionEvent裏是一樣的,可以去參考源碼

清單文件裏如下的代碼

android:windowSoftInputMode="stateVisible|stateAlwaysVisible" 

這種其實不合理,正確的寫法,state和adjust應該每樣最多一個,或者不寫。
那麼這樣寫了也不會錯,反正就是你寫的2個值它進行或操作,最後得到的結果,如果在1到5之間,那麼state自然有效,如果不在,那就無效的。
上邊2個就是4|5 或操作,也就是二進制100和101,最後結果還是101

題外話

本人測試沒發現有啥問題,如果有人使用中發現有問題,麻煩告知一下,我好處理。
這個類,也是很久以前不知道哪裏找的,做了下修改

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章