Android监听软键盘的显示与隐藏

原创 2016年05月30日 14:47:07

自从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.

版权声明:本文为【吧主】原创文章,欢迎转载,转载请注明出处。【http://blog.csdn.net/xiaole0313】

【Android应用】【监听软键盘弹起与关闭】

背景: 在很多App开发过程中需要在Activity中监听Android设备的软键盘弹起与关闭,但是Android似乎没有提供相关的的监听API给我们来调用,本文提供了一个可行的办法来监听软键盘的弹起...
  • bear_huangzhen
  • bear_huangzhen
  • 2015年05月21日 20:35
  • 60104

Android App监听软键盘按键的三种方式

前言: 我们在android手机上面有时候会遇到监听手机软键盘按键的时候,例如:我们在浏览器输入url完毕后可以点击软键盘右下角的“GO”按键加载url页面;在点击搜索框的时候,点击右下角的sear...
  • zhufuing
  • zhufuing
  • 2014年02月08日 10:35
  • 95389

Android软键盘(六)如何监听到软件盘显示与隐藏的事件

有时候我们需要监听软件盘隐藏事件。但是官方并没有提供相关的监听回调,这时我们就需要通过计算布局来判断软键盘的关闭事件了。思路与上一篇文章Android软键盘(五)如何判断软键盘是否显示相似。 看效果图...
  • sinat_31311947
  • sinat_31311947
  • 2016年12月28日 22:01
  • 5910

史上最全:安卓监听软键盘打开或者关闭

史上最全:安卓监听软键盘打开或者关闭SoftKeyboard open and close listener in an activity in Android?问题:我有一个Activity,里面有...
  • gusgao
  • gusgao
  • 2016年09月11日 16:43
  • 9418

监听软键盘的显示与隐藏

硬键盘显示隐藏的事件监听 对于有硬键盘的设备,是会产生运行时的配置变更(Runtime Config Changes),因此可以通过Activity#onConfigurationChanged...
  • u013749540
  • u013749540
  • 2016年05月09日 10:25
  • 688

(原创)EditText软键盘弹出关闭等使用总结

(原创)EditText软键盘弹出关闭等使用总结 1.关于EditText常用属性设置: (1).去除其默认划线背景方式:设置背景色透明即可 android:background="#00000...
  • lnn368
  • lnn368
  • 2016年04月20日 15:24
  • 6916

如何监听软键盘的弹出、隐藏(亲测可用)

看了N多文章,终于找到了答案第一步这篇文章解决了在不是全屏模式下,监听软键盘弹出隐藏,但是在全屏模式下,无效 注意:必须设置 android:windowSoftInputMode="adj...
  • Android_Study_OK
  • Android_Study_OK
  • 2016年09月24日 00:55
  • 4537

Android监听软键盘打开收起事件(软键盘自带收起按钮)

最近在公司开发cocos2dx上的Android输入框控件,遇到软键盘的事件监听,通常软键盘的收起方式大致3种: 1.点击软键盘右下角的Return按钮(系统收起) 2.输入框焦点时按返回按钮(系...
  • chenhuakang
  • chenhuakang
  • 2016年07月21日 13:54
  • 5319

检测软键盘的弹起与隐藏【绝对经典,好用】

转自:http://www.eoeandroid.com/thread-157446-1-1.html 今天看到社区里面有人问关于如何检测软键盘的弹起和隐藏事件。正确...
  • liangguo03
  • liangguo03
  • 2012年03月04日 11:46
  • 16647

安卓开发技术:监听软键盘的显示与隐藏

自从2007年乔帮主横空出世推出iPhone后,智能手机就都变成了触摸屏,且屏幕越来越大。输入自然也就通过软件来解决,现在来说绝大多数智能设备都是通过软键盘来做用户输入。在日常的开发过程中难免会跟软键...
  • hitlion2008
  • hitlion2008
  • 2015年12月03日 23:32
  • 3918
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android监听软键盘的显示与隐藏
举报原因:
原因补充:

(最多只允许输入30个字)