Android优雅地判断软键盘弹出状态

版权声明:个人原创,欢迎转载。 https://blog.csdn.net/chuyangchangxi/article/details/84972463

一、为什么要判断软键盘弹出状态

神马笔记在完成笔记编辑时,会对编辑界面进行截图以作为笔记的图标。为了保证图标的一致性,需要在关闭软键盘后进行截图,否则会产生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

猜你喜欢

转载自blog.csdn.net/chuyangchangxi/article/details/84972463