前言
最近重新設計了一遍專案中的搜尋欄,但是目前這個輸入框每次填完搜尋內容,都需要去按下右邊的搜尋按鈕,感覺比較麻煩。但是看到很多應用,填完內容後輸入框右下角按鈕直接會變成搜尋按鈕。平時對這方面瞭解比較少,故在此總結下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
- 上面提到必須要設定
android:singleLine="true"
,但是我們想換行怎麼辦? 在程式碼中這樣設定就行了:
mEditText.setHorizontallyScrolling(false);
mEditText.setMaxLines(4);
複製程式碼
在佈局檔案中設定是無效的,應該也是優先順序的問題。加第一行程式碼是因為EditTextview內容超過一行是不會換行的而是左右滾動。
-
想自定義鍵盤上事件響應的按鈕是不行的,只能從已經設定好的幾個動作中選擇,由於第三方輸入法的不同,有些動作不會響應,顯示圖示也不盡相同。
-
我們是根據
actionId
而不是直接採用mEditText.getImeOptions()
,兩個值初始時是一樣的,但第一次軟體盤事件響應後,後者值就變了,而actionId還是原來的。軟鍵盤右下角按鈕的動作是取決於actionId
的,這樣我們也就不需要在鍵盤消失後將mEditText
的動作還原。