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给我们来调用,本文提供了一个可行的办法来监听软键盘的弹起...

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

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

精选:深入理解 Docker 内部原理及网络配置

网络绝对是任何系统的核心,对于容器而言也是如此。Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,如 Docker 的镜像管理。然而,Docker的网络一直以来都比较薄弱,所以我们有必要深入了解Docker的网络知识,以满足更高的网络需求。

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

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

Android中软键盘监听

译文:https://pspdfkit.com/blog/2016/keyboard-handling-on-android/ 在Android中使用Keyboard有时非常纠结。曾经有个项目在...

Android 监听键盘的弹出与关闭,收起

新建键盘的监听类 import android.app.Activity; import android.view.View; import android.view.ViewTreeObserver...

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

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

android EditText软键盘显示隐藏以及"监听"

一、写此文章的起因 本人在做类似于微信、易信等这样的聊天软件时,遇到了一个问题。聊天界面最下面一般类似于如图1这样(这里只是显示了最下面部分,可以参考微信等),有输入文字的EditText和表情按钮等...

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

最近在做项目时候,对软键盘的监听网上查询好的资料,最好看到 http://toughcoder.net/blog/2015/10/09/android-trick-detect-soft-keyboa...

Android windowSoftInputMode软键盘显示和隐藏的监听和实现

现在在公司,其实今天不用加班,但留下来写篇博客。今天做了一个关于聊天输入框和表情框的Demo,主要是为了使用软件盘的显示和隐藏。下面是效果图,(只是为了弄清原理,界面比较丑)             ...
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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