前言
最近重新设计了一遍项目中的搜索栏,但是目前这个输入框每次填完搜索内容,都需要去按下右边的搜索按钮,感觉比较麻烦。但是看到很多应用,填完内容后输入框右下角按钮直接会变成搜索按钮。平时对这方面了解比较少,故在此总结下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;
}
});
复制代码
看下效果:
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
- 上面提到必须要设置
android:singleLine="true"
,但是我们想换行怎么办? 在代码中这样设置就行了:
mEditText.setHorizontallyScrolling(false);
mEditText.setMaxLines(4);
复制代码
在布局文件中设置是无效的,应该也是优先级的问题。加第一行代码是因为EditTextview内容超过一行是不会换行的而是左右滚动。
-
想自定义键盘上事件响应的按钮是不行的,只能从已经设置好的几个动作中选择,由于第三方输入法的不同,有些动作不会响应,显示图标也不尽相同。
-
我们是根据
actionId
而不是直接采用mEditText.getImeOptions()
,两个值初始时是一样的,但第一次软件盘事件响应后,后者值就变了,而actionId还是原来的。软键盘右下角按钮的动作是取决于actionId
的,这样我们也就不需要在键盘消失后将mEditText
的动作还原。