1. 程式人生 > >Android優雅地判斷軟鍵盤彈出狀態

Android優雅地判斷軟鍵盤彈出狀態

Android優雅地判斷軟鍵盤彈出狀態

一、為什麼要判斷軟鍵盤彈出狀態

神馬筆記在完成筆記編輯時,會對編輯介面進行截圖以作為筆記的圖示。為了保證圖示的一致性,需要在關閉軟鍵盤後進行截圖,否則會產生2種尺寸的截圖大小。

因此,需要判斷軟鍵盤是否彈出。如果軟鍵盤彈出,則先關閉軟鍵盤,使用者才能退出編輯。

二、已有的判斷方案

http://www.cnblogs.com/shelly-li/p/5639833.html

https://blog.csdn.net/yijiaodingqiankun/article/details/81085167?utm_source=blogxgwz5

https://blog.csdn.net/sinat_31311947/article/details/53899166

https://blog.csdn.net/javazejian/article/details/52126391

所有方案一致指向,根據佈局變化來判斷軟鍵盤是否彈出是最穩妥的實現方案。

三、設計新的方案

首先,需要設定Activity的windowSoftInputMode屬性為adjustResize

當軟鍵盤狀態發生變化時,佈局會相應地發生變化。再根據佈局變化來判斷軟鍵盤狀態。

其次,監聽Activity的android.R.id.content控制元件的佈局變化。

android.R.id.content是每個Activity的使用者控制元件的容器,存在於每一個Activity中,所以我們監聽android.R.id.content的變化可以適應所有的Activity。

再來,使用LifecycleObserver來感知Activity的狀態變化,從而決定何時啟動佈局變化監聽。

最後,使用ActivityLifecycleCallbacks關心其他Activity的變化,獲取Bottom的最大值,比較當前Bottom值以及最大Bottom值,從而判斷軟鍵盤的狀態。

四、實現效果

在這裡插入圖片描述

注意左上角的變化。

軟鍵盤彈出時,顯示為“完成”按鈕。

軟鍵盤關閉時,顯示為“返回”圖示。

五、完整程式碼

package club.andnext.helper;

import android.app.Activity;
import android.app.Application;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;

/**
 *
 */
public class SoftInputHelper implements LifecycleObserver,
        Application.ActivityLifecycleCallbacks,
        ViewTreeObserver.OnGlobalLayoutListener {

    private static final String TAG = SoftInputHelper.class.getSimpleName();

    int bottom;

    boolean visible;

    Rect rect;

    OnSoftInputListener onSoftInputListener;

    FragmentActivity context;

    public SoftInputHelper(FragmentActivity context) {
        this.context = context;

        this.bottom = 0;
        this.visible = false;

        this.rect = new Rect();

        context.getLifecycle().addObserver(this);
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    public void onCreate() {
        context.getApplication().registerActivityLifecycleCallbacks(this);
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onStart() {
        ViewTreeObserver observer = getViewTreeObserver(context);
        if (observer != null && observer.isAlive()) {
            observer.addOnGlobalLayoutListener(this);
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void onStop() {
        ViewTreeObserver observer = getViewTreeObserver(context);
        if (observer != null && observer.isAlive()) {
            observer.removeOnGlobalLayoutListener(this);
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    public void onDestroy() {
        context.getApplication().unregisterActivityLifecycleCallbacks(this);

        context.getLifecycle().removeObserver(this);
    }

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {

    }

    @Override
    public void onActivityStarted(Activity activity) {

    }

    @Override
    public void onActivityResumed(Activity activity) {

    }

    @Override
    public void onActivityPaused(Activity activity) {

    }

    @Override
    public void onActivityStopped(Activity activity) {
        this.updateBottom(activity);
    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {

    }

    @Override
    public void onActivityDestroyed(Activity activity) {

    }

    @Override
    public void onGlobalLayout() {

        {
            this.updateBottom(context);
        }

        View target = getView(context);
        if (target != null) {

            target.getGlobalVisibleRect(rect);
            boolean result = rect.bottom < bottom;

            if (this.visible ^ result) {
                this.visible = result;

                if (onSoftInputListener != null) {
                    onSoftInputListener.onSoftInputChanged(this, visible);
                }
            }

        }
    }

    public int getBottom() {
        return bottom;
    }

    public void setOnSoftInputListener(OnSoftInputListener listener) {
        this.onSoftInputListener = listener;
    }

    void updateBottom(Activity activity) {
        View view = getView(activity);
        if (view != null) {
            view.getGlobalVisibleRect(rect);

            bottom = (bottom < view.getBottom())? view.getBottom(): bottom;
            bottom = (bottom < rect.bottom)? rect.bottom: bottom;
        }

        Log.v(TAG, "bottom = " + bottom);
    }

    View getView(Activity activity) {
        View view = activity.getWindow().getDecorView().findViewById(android.R.id.content);
        return view;
    }

    ViewTreeObserver getViewTreeObserver(Activity activity) {
        View view = getView(activity);
        if (view == null) {
            return null;
        }

        return view.getViewTreeObserver();
    }

    /**
     *
     */
    public interface OnSoftInputListener {

        void onSoftInputChanged(SoftInputHelper helper, boolean visible);

    }
}

六、核心程式碼

  1. 計算最大Bottom值

需要最大Bottom值作為參考值,比較當前bottom及最大bottom,從而判斷軟鍵盤狀態。

    void updateBottom(Activity activity) {
        View view = getView(activity);
        if (view != null) {
            view.getGlobalVisibleRect(rect);

            bottom = (bottom < view.getBottom())? view.getBottom(): bottom;
            bottom = (bottom < rect.bottom)? rect.bottom: bottom;
        }

        Log.v(TAG, "bottom = " + bottom);
    }
  1. 判斷軟鍵盤是否彈出

將當前bottom與最大bottom比較,從而得出結論。

    @Override
    public void onGlobalLayout() {

        {
            this.updateBottom(context);
        }

        View target = getView(context);
        if (target != null) {

            target.getGlobalVisibleRect(rect);
            boolean result = rect.bottom < bottom;

            if (this.visible ^ result) {
                this.visible = result;

                if (onSoftInputListener != null) {
                    onSoftInputListener.onSoftInputChanged(this, visible);
                }
            }

        }
    }

七、下載地址

神馬筆記最新版本:【whatsnote_lastest.apk