Android 軟鍵盤響應事件解析

前言

最近從新設計了一遍項目中的搜索欄,可是目前這個輸入框每次填完搜索內容,都須要去按下右邊的搜索按鈕,感受比較麻煩。可是看到不少應用,填完內容後輸入框右下角按鈕直接會變成搜索按鈕。平時對這方面瞭解比較少,故在此總結下Android軟鍵盤響應事件。java

imeOptions

要想實現這個小功能,就不得不說這個屬性,對應代碼中的方法是:android

void setImeOptions(int imeOptions)int getImeOptions()bash

imeOptions經常使用的有如下幾種:ide

  • actionDone 完成
  • actionGo 前進
  • actionNext 下一項
  • actionNone 無動做
  • actionPrevious 上一項
  • actionSearch 搜索
  • actionUnspecified 未指定
  • actionSend 發送

意思都很好理解 ,其中默認動做是actionUnspecified,在代碼中這些值存儲在EditorInfo類中,以IME開頭,如EditorInfo.IME_ACTION_GO。因此上面咱們須要實現的搜索功能只是這些動做中的一種。另外還須要設置一個屬性,否則沒法生效:佈局

android:singleLine="true"ui

個人理解是,若是不設置限制單行,那麼右下角會被換行按鈕佔用,這個功能是高於鍵盤動做事件優先級的。 另外可能有些輸入法還要求設置: android:inputType="text"this

不過我實測不設置也能夠(固然爲了兼容性仍是建議設一下)。好了,這樣設完以後咱們就能夠在代碼中監聽這個動做的事件了:spa

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;
                }
            }
            
    ......執行默認動做
複製代碼

在源碼中看出,系統實現的默認動做只有三個:code

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的動做還原。

相關文章
相關標籤/搜索