Android 软键盘响应事件解析

前言

最近重新设计了一遍项目中的搜索栏,但是目前这个输入框每次填完搜索内容,都需要去按下右边的搜索按钮,感觉比较麻烦。但是看到很多应用,填完内容后输入框右下角按钮直接会变成搜索按钮。平时对这方面了解比较少,故在此总结下Android软键盘响应事件。

imeOptions

要想实现这个小功能,就不得不说这个属性,对应代码中的方法是:

void setImeOptions(int imeOptions)int getImeOptions()

imeOptions常用的有以下几种:

  • actionDone 完成
  • actionGo 前进
  • actionNext 下一项
  • actionNone 无动作
  • actionPrevious 上一项
  • actionSearch 搜索
  • actionUnspecified 未指定
  • actionSend 发送

意思都很好理解 ,其中默认动作是actionUnspecified,在代码中这些值存储在EditorInfo类中,以IME开头,如EditorInfo.IME_ACTION_GO。所以上面我们需要实现的搜索功能只是这些动作中的一种。另外还需要设置一个属性,不然无法生效:

android:singleLine="true"

我的理解是,如果不设置限制单行,那么右下角会被换行按钮占用,这个功能是高于键盘动作事件优先级的。 另外可能有些输入法还要求设置: android:inputType="text"

不过我实测不设置也可以(当然为了兼容性还是建议设一下)。好了,这样设完之后我们就可以在代码中监听这个动作的事件了:

 mEditText.setOnEditorActionListener(new EditText.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                    String text = mEditText.getText().toString();
                    if (TextUtils.isEmpty(text)) {
                        Toast.makeText(MainActivity.this, "请输入关键字", Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(MainActivity.this, "输入了" + text, Toast.LENGTH_SHORT).show();
                    }
                    return true;
                }
                return false;
            }
        });
复制代码

看下效果:

返回true说明消耗了这个事件,不然会继续执行这个动作默认的操作,这点在源码上很容易体现:

 public void onEditorAction(int actionCode) {
        final Editor.InputContentType ict = mEditor == null ? null : mEditor.mInputContentType;
        if (ict != null) {
            if (ict.onEditorActionListener != null) {
                if (ict.onEditorActionListener.onEditorAction(this,
                        actionCode, null)) {
                    return;
                }
            }
            
    ......执行默认动作
复制代码

在源码中看出,系统实现的默认动作只有三个:

 if (actionCode == EditorInfo.IME_ACTION_NEXT) {
                View v = focusSearch(FOCUS_FORWARD);
                if (v != null) {
                    if (!v.requestFocus(FOCUS_FORWARD)) {
                        throw new IllegalStateException("focus search returned a view "
                                + "that wasn't able to take focus!");
                    }
                }
                return;

            } else if (actionCode == EditorInfo.IME_ACTION_PREVIOUS) {
                View v = focusSearch(FOCUS_BACKWARD);
                if (v != null) {
                    if (!v.requestFocus(FOCUS_BACKWARD)) {
                        throw new IllegalStateException("focus search returned a view "
                                + "that wasn't able to take focus!");
                    }
                }
                return;

            } else if (actionCode == EditorInfo.IME_ACTION_DONE) {
                InputMethodManager imm = InputMethodManager.peekInstance();
                if (imm != null && imm.isActive(this)) {
                    imm.hideSoftInputFromWindow(getWindowToken(), 0);
                }
                return;
            }
        }
复制代码

有一点需要提一下:上面代码这么设置,点完搜索按钮,事件响应了但输入框是不会消失的,所以这里我们可以取巧下:处理完我们的动作后直接把动作设置为IME_ACTION_DONE,然后返回false,这样就可以继续执行EditorInfo.IME_ACTION_DONE中的代码,从而实现在点完搜索按钮后隐藏输入框:

 mEditText.setOnEditorActionListener(new EditText.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                    String text = mEditText.getText().toString();
                    if (TextUtils.isEmpty(text)) {
                        //如果没输入内容就不隐藏了
                        Toast.makeText(MainActivity.this, "请输入关键字", Toast.LENGTH_SHORT).show();
                        return true;
                    } else {
                        Toast.makeText(MainActivity.this, "输入了" + text, Toast.LENGTH_SHORT).show();
                        mEditText.setImeOptions(EditorInfo.IME_ACTION_DONE);
                        return false;
                    }

                }
                return false;
            }
        });
复制代码

小tips

  1. 上面提到必须要设置android:singleLine="true",但是我们想换行怎么办? 在代码中这样设置就行了:
mEditText.setHorizontallyScrolling(false);
mEditText.setMaxLines(4);
复制代码

在布局文件中设置是无效的,应该也是优先级的问题。加第一行代码是因为EditTextview内容超过一行是不会换行的而是左右滚动。

  1. 想自定义键盘上事件响应的按钮是不行的,只能从已经设置好的几个动作中选择,由于第三方输入法的不同,有些动作不会响应,显示图标也不尽相同。

  2. 我们是根据actionId而不是直接采用mEditText.getImeOptions(),两个值初始时是一样的,但第一次软件盘事件响应后,后者值就变了,而actionId还是原来的。软键盘右下角按钮的动作是取决于actionId的,这样我们也就不需要在键盘消失后将mEditText的动作还原。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值