对Android 软键盘向下的监听

Posted yxhuangCH

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对Android 软键盘向下的监听相关的知识,希望对你有一定的参考价值。

因为业务需要,有时候我们好监听软键盘向下的动作,当我们按下向下的按钮时,可以进行监听,从而执行相应的动作。
这里写图片描述

于是我们写下下面的代码

 @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK){
            Log.i(TAG, "onKeyDown");
        }
        return super.onKeyDown(keyCode, event);
    }

我们按下向下的按钮,滴,没反应。再按一次,滴,握草,直接退出了,这个时候才有 log 打印出来。这个 log 是退出当前 Activity, 而不是软键盘向下的。

如果没有想到好的解决方案,就问 google , 于是我们得到了解决方法,就是对 Edittext.onKeyPreIme() 方法重写

/**
 *  拦截键盘向下的 EditTextView
 */
public class TextEditTextView extends EditText {
    public TextEditTextView(Context context) {
        super(context);
    }

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

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


    @Override
    public boolean onKeyPreIme(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == 1) {
            Log.i("main_activity", "键盘向下 ");
            super.onKeyPreIme(keyCode, event);
            return false;
        }
        return super.onKeyPreIme(keyCode, event);
    }
}

在布局中

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    android:id="@+id/activity_main"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white">


    <com.yxhuang.myapplication.TextEditTextView
        android:id="@+id/edt_text"
        android:layout_width="match_parent"
        android:hint="测试"
        android:layout_marginTop="30dp"
        android:textColorHint="@android:color/black"
        android:layout_height="wrap_content"/>

</RelativeLayout>

这里写图片描述

点击向下后,可以看到 log

这里写图片描述

这是键盘向下的监听,我们得到了,然后可以执行相应的动作。

作为一个程序员,我们不仅要知道怎样做,还应该知道为什么会这样。这个问题就涉及到 Android 输入系统,详情见上一篇博文 Android 输入系统

为什么 重写 Activity.onKeyDown() 方法为什么没有用?

根据 Android 输入系统 一文,我们知道事件的流水线处理顺序 这里写图片描述

Ime 是键盘输入法, ViewPreImeStage 是在输入法之前,ImeStage 是输入法处理,ViewPostImeStage 才是最终传递到 Activity.onKeyDown() 的。

ViewPreImeStage 中可以将键盘向下的事件传递到 View, 而到了 ViewPostImeStage 则没有,那应该是有东西消耗了这个事件。当我们按下向下的按钮,键盘会收起来,显然是键盘消耗了这个事件。

我们看看 ImeStage 的源码

 /**
     * Delivers input events to the ime.
     * Does not support pointer events.
     */
    final class ImeInputStage extends AsyncInputStage
            implements InputMethodManager.FinishedInputEventCallback {
        public ImeInputStage(InputStage next, String traceCounter) {
            super(next, traceCounter);
        }

        @Override
        protected int onProcess(QueuedInputEvent q) {
            if (mLastWasImTarget) {
                // 获取 InputMethodManager 实例
                InputMethodManager imm = InputMethodManager.peekInstance();
                if (imm != null) {
                    final InputEvent event = q.mEvent;
                    // dispatchInputEvent 方法处理了事件
                    int result = imm.dispatchInputEvent(event, q, this, mHandler);
                    if (result == InputMethodManager.DISPATCH_HANDLED) {
                        return FINISH_HANDLED;
                    } else if (result == InputMethodManager.DISPATCH_NOT_HANDLED) {
                        return FINISH_NOT_HANDLED;
                    } else {
                        return DEFER; // callback will be invoked later
                    }
                }
            }
            return FORWARD;
        }

        @Override
        public void onFinishedInputEvent(Object token, boolean handled) {
            QueuedInputEvent q = (QueuedInputEvent)token;
            if (handled) {
                finish(q, true);
                return;
            }
            forward(q);
        }
    }

我们看到如果 InputMethodeManager.dispatchInputEvent(…) 方法返回的结果是
InputMethodManager.DISPATCH_HANDLED 则结束事件的传递。事件就传递不到 ViewPostImeStage, 从而也就传递不到 Activity.onKeyDown() 中了。

到这来我们终于知道了为什么重写 Activity.onKeyDown() 方法没用了,想要监听键盘向下的事件,需要重写 Edittext.onKeyPreime() 方法,在这个方法里进行监听了。

以上是关于对Android 软键盘向下的监听的主要内容,如果未能解决你的问题,请参考以下文章

Android 手机软键盘的弹起和关闭的监听

完美解决android软键盘监听

完美解决android软键盘监听1

在片段替换上显示/隐藏 Android 软键盘

为啥Android不会暂停视图完全被软键盘挡住的片段?

Android之监听手机软键盘弹起与关闭