代码很简单,可以直接复制粘贴。

代码如下:

private void setListenerToRootView() {final View rootView = getWindow().getDecorView().findViewById(android.R.id.content);
    rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {@Override
        public void onGlobalLayout() {LogUtils.d(TAG, "[onGlobalLayout] .. in ..");
            boolean mKeyboardUp = isKeyboardShown(rootView);
            if (mKeyboardUp) {// LogUtils.d(TAG, "键盘弹出..");
                Toast.makeText(LoginActivity.this, "键盘弹出", Toast.LENGTH_SHORT).show();
            } else {//LogUtils.d(TAG, "键盘收起..");
                Toast.makeText(LoginActivity.this, "键盘收起", Toast.LENGTH_SHORT).show();
            }}});
}private boolean isKeyboardShown(View rootView) {final int softKeyboardHeight = 100;
    Rect r = new Rect();
    rootView.getWindowVisibleDisplayFrame(r);
    DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
    int heightDiff = rootView.getBottom() - r.bottom;
    return heightDiff > softKeyboardHeight * dm.density;
}

原理请参照:http://blog.csdn.net/xiaole0313/article/details/51537809

即如下:

自从2007年乔帮主横空出世推出iPhone后,智能手机就都变成了触摸屏,且屏幕越来越大。输入自然也就通过软件来解决,现在来说绝大多数智能设备都是通过软键盘来做用户输入。在日常的开发过程中难免会跟软键盘打交道,比如强制显示或者强制隐藏等,也有些时候想要在键盘隐藏或者显示的时候做一点事情,这就需要准确的知道键盘的事件,这篇文章就来详细讨论一下Android下面如何做到监听键盘的事件。

硬键盘显示隐藏的事件监听

对于有硬键盘的设备,是会产生运行时的配置变更(Runtime Config Changes),因此可以通过Activity#onConfigurationChanged)回调来处理:

首先,要在AndroidManifest中给activity加上configChanges=“keyboardHidden”。

然后,在代码中,处理:

1
2
3
4
5
6
7
8
9
10
11
@Override
public void onConfigurationChanged(Configuration newConfig) {    super.onConfigurationChanged(newConfig);

    // Checks whether a hardware keyboard is available
    if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {        Toast.makeText(this, "keyboard visible", Toast.LENGTH_SHORT).show();
    } else if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {        Toast.makeText(this, "keyboard hidden", Toast.LENGTH_SHORT).show();
    }
}

需要注意的是,要用Configuration#hardKeyboardHidden而不是Configuration#keyboardHidden,因为只有当硬键盘状态变化时才会回调onConfigurationChanged。

软键盘显示隐藏事件监听

现在的Android设备很少才会有硬键盘,绝大多数都是软键盘,而SDK和API中却没有软键盘隐藏变化的相关事件,没有直接支持不代表做不到。我们通过其他的方式还是可以做到监听软键盘显示与隐藏状态变化的。

override onKeyPreIme

当EditText获得焦点时,或者用户点击时,都会把软键盘弹起来(2.x版本长按MENU也可以强制弹出软键盘)。但是,隐藏软键盘一般都是BACK键,或者键盘自身提供隐藏的按扭,再有就是用代码强制隐藏。对于BACK键还是可以处理的,因为这属于事件(KeyEvent),是能监听到的。

核心原理

子例化EditText,并覆写方法onKeyPreIme)。这个方法能在输入法前面拦掉事件,从而可以做一些事情:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class KeyPreImeEditText extends EditText {    public KeyPreImeEditText(Context context) {        super(context);
    }

    public KeyPreImeEditText(Context context, AttributeSet attrs) {        super(context, attrs);
    }

    public KeyPreImeEditText(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {        if (keyCode == KeyEvent.KEYCODE_BACK) {            Log.e("keyboard", "onKeyPreIme we got back");
        }
        return super.onKeyPreIme(keyCode, event);
    }
}

优点

简单粗暴,都是SDK支持的方法和事件,所以不会有兼容性等蛋疼的问题。

缺点

这仅在输入法前拦截到BACK事件,而前面提到BACK仅是能让软键盘隐藏掉的一个方式而已,所以这个方法是不能够完全做到监听软键盘隐藏状态变化的。这个方法仅适用于想拦截BACK,做一些其他事情的场景。

override根布局的onMeasure

另外的思路就是观察软键盘引起的布局变化,比如软键盘弹起时Activity的整体布局都会发生变化。

核心原理

子例化Activity的根布局(比如LinearLayout或者RelativeLayout,然后覆写其onMeasure)方法,在其中判断View的当前高度与其本应有的高度,如果当前高度小于本应有的高度,则表明软键盘在:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class KeyboardAwareLinearLayout extends LinearLayout {    public KeyboardAwareLinearLayout(Context context) {        super(context);
    }

    public KeyboardAwareLinearLayout(Context context, AttributeSet attrs) {        super(context, attrs);
    }

    public KeyboardAwareLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        final int proposedHeight = MeasureSpec.getSize(heightMeasureSpec);
        final int actualHeight = getHeight();

        if (actualHeight > proposedHeight) {            Log.e("keyboard", "guess keyboard is shown");
        } else {            Log.e("keyboard", "guess keyboard has been hidden");
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

优点

能够真正实现对软键盘隐藏和显示的监听,也不算复杂。

缺点

这个基于的原理是键盘对Activity的布局产生影响的情况,而这又受到其他条件控制。activity的属性windowSoftInputMode控制着软键盘与布局之间的影响关系,对于adjustPan以及全屏模式的adjustResize这种方法就失效了,因为这二种情况软键盘弹起时,布局是不会发生变化的,二种height值是一样的,自然无法分辨。

监听GlobalLayout

与上面的思路差不多,只不是监听GlobalLayout变化,然后根据布局高度与屏幕高度之差来判断。

注意:要记得把注册的GlobalLayoutListener再反注册掉。

计算根布局的高度差

判断的依据是根布局与DectorView之间的差值,在正常情况下应该等于status bar高度与action bar高度之和。当软键盘弹起时则会大于此值。

核心原理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private boolean mKeyboardUp;

private void setListenerToRootView() {        final View rootView = getWindow().getDecorView().findViewById(android.R.id.content);
        rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {            @Override
            public void onGlobalLayout() {                final int headerHeight = getActionBarHeight() + getStatusBarHeight();
                int heightDiff = rootView.getRootView().getHeight() - rootView.getHeight();
                if (heightDiff > headerHeight) {                    Log.e("keyboard", "keyboard is up");
                    if (!mKeyboardUp) {                        mKeyboardUp = true;
                    }
                } else if (mOpen) {                    Log.e("keyboard", "keyboard is hidden");
                    mKeyboardUp = false;
                }
            }
        });
    }

这段代码需要好好解释下:

  • android.R.id.content 通过这个id可以获得一个View的根布局,而不必要知道它具体的id。可以参考这个讨论。
  • rootView 这个View是Activity的根布局,除去了actionbar的部分,是一个FrameLayout,注意这个并不是setContentView中设置的布局。rootView的第一个子View(rootView.getChildAt(0))就是setContentView()设置的布局。可以参考这个讨论。
优点

不用子例化,不依赖于现有代码中的成员,可以直接插入到任何代码中。

缺点

本质上这跟上一个方法是一样的。因此对于adjustPan和全屏的adjustResize二种情况是无效的。针对这二种情况heightDiff不会变化。

计算根布局的的底部空隙

其实所有的方法都是为了发现软键盘对布局的影响,从而判断软键盘的显示和隐藏。还有一种方法就判断根布局的可视区域与屏幕底部的差值,如果这个差大于某个值,可以认定键盘弹起了。

核心原理
1
2
3
4
5
6
7
8
private boolean isKeyboardShown(View rootView) {        final int softKeyboardHeight = 100;
        Rect r = new Rect();
        rootView.getWindowVisibleDisplayFrame(r);
        DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
        int heightDiff = rootView.getBottom() - r.bottom;
        return heightDiff > softKeyboardHeight * dm.density;
}

得到的Rect就是根布局的可视区域,而rootView.bottom是其本应的底部坐标值,如果差值大于我们预设的值,就可以认定键盘弹起了。这个预设值是键盘的高度的最小值。这个rootView实际上就是DectorView,通过任意一个View再getRootView就能获得。

优点

适用所有情况,包括adjustPan和全屏的adjustResize也能准确判断出来。

结论

如果真的需要监听软键盘显示与隐藏的事件就可以通过上面的提到的最后一种方式来实现,简单方便且可靠,唯一要注意的就是要反注册掉所注册的GlobalLayoutListener.

Android完美检测键盘弹出/收起相关推荐

  1. Android判断软键盘弹出并隐藏的简单完美解决方案

    Android判断软键盘弹出并隐藏的简单完美解决方案 参考文章: (1)Android判断软键盘弹出并隐藏的简单完美解决方案 (2)https://www.cnblogs.com/thare1307/ ...

  2. (小技巧)h5 手机键盘弹出收起的处理

    本文转载于思否社区专栏:随笔 作者:hzzly 前言:前段时间也是应项目的需求开始了 h5 移动端的折腾之旅,在目前中台的基础上扩展了两个 ToC 移动端项目,下面就是在 h5 移动端表单页面键盘弹出 ...

  3. android实现软键盘弹出,editText随键盘上移,背景不动

    android实现软键盘弹出,editText随键盘上移,背景不动 前段时间有个妹子问我如题的需求,我就想,这种东西网上不是很多吗,自己试过才发现,基本都不行,各种设置配置文件的windowSoftI ...

  4. 安卓键盘事件监听,键盘弹出收起

    一.键盘事件监听 1.在mainifest.xml 中设置activity模式 ```<activityandroid:name=".ui.activity.MainActivity& ...

  5. Android中软键盘弹出时关于布局的问题

    当在Android的layout设计里面如果输入框过多,则在输入弹出软键盘的时候,下面的输入框会有一部分被软件盘挡住,从而不能获取焦点输入. 解决办法: 方法一:在你的activity中的oncrea ...

  6. android键盘顶起布局原理,android如何把键盘弹出不影响布局?

    我想只把键盘和输入框那个layout弹上去 只有键盘弹出,而且toolbar的颜色会延生到下面 这是设置为adjustPan以后,会把整个界面顶上去,我只想顶输入框 activity_chat.xml ...

  7. Android中软键盘弹出可能遮挡布局

    当在Android的layout设计里面如果输入框过多,则在输入弹出软键盘的时候,下面的输入框会有一部分被软件盘挡住,从而不能获取焦点输入. 解决办法: 方法一:在你的activity中的oncrea ...

  8. 简单可用 Android 安卓软键盘弹出、隐藏监听方法回调

    工具类 import android.app.Activity import android.graphics.Rect import android.view.ViewTreeObservercla ...

  9. android判断键盘是否弹出窗口,Android判断软键盘弹出并隐藏的简单完美解决方法(推荐)...

    最近项目中有一个编辑框,下面是个ListView.在触发编辑框弹出软键盘后,ListView还能滑动,并且ListView的item还能响应单击.这样的体验效果很不好.于是便想在滑动或单击item时判 ...

最新文章

  1. 面试定心丸:AI知识点备忘录(包括ML、DL、Python、Pandas等)
  2. android流量监控步骤_Android流量网络监控设计(超级实用版).doc
  3. 如何在Visual Studio 2010中使用CppUTest建立TDD的Code Kata的环境
  4. Fabricjs在Canvas上使用路径Path绘制不规则图形
  5. [转]VS2008中开发智能设备程序的一些总结
  6. pytorch几种损失函数CrossEntropyLoss、NLLLoss、BCELoss、BCEWithLogitsLoss、focal_loss、heatmap_loss
  7. centos7安装redis的正确姿势
  8. 多模态中的Prompt范式:从CLIP、CoOp到CLIP-adapter
  9. 自百度2012吧——这些都是巧合吗
  10. 更改matlab默认启动路径
  11. JQuery 中选择多选择框,和单选框,实现获取相应选择的值
  12. mysql中主从复制包括什么意思_Mysql主从复制作用和工作原理
  13. 腾讯位置服务地图选点这个怎么在小程序里面更新呀?
  14. Ubuntu下的提示信息彩色显示
  15. 【资料篇】你需要掌握SEO的8个常用知识点
  16. php 转通达信数据格式,通达信数据格式
  17. 玩转小米盒子1:选购指南及应用推荐
  18. linux wget 安装包,linux系统下安装wget。
  19. 使用ODAC将SqlServer数据库同步到oracle数据库
  20. ultraISO方式制作win10安装U盘

热门文章

  1. Google下载速度太慢
  2. SIM卡ICCID的编码方案
  3. 怎么用win10自带虚拟机
  4. XZ原厂C/DC升压IC移动电源常用升压芯片
  5. 犀牛书第2章 JavaScript词法结构
  6. 你所不知道的noscript标签
  7. Centos 7.6 安装bbr(2019.06.11)
  8. 【教程】微信公众号与小程序主体变更看这篇就够了
  9. 操作系统结课论文——进程的概念与状态
  10. 项目上有个红色感叹号