EditTextのActionButtonで入力の完了を通知する方法を紹介します。
ActionButtonとは
EditTextは入力デバイス(インプットメソッド、具体的にはキーボードなど)から入力されたテキストを取得するウィジェットです。
EditTextへ入力されたテキストを確定する際に、HWキーボードではEnterキーを押下したりします。
SWキーボードでも同様ですが、さらにEnterキーの代わりにActionButtonを定義できるようになっていて、入力の完了をActionButtonの押下で受け取ることが出ます。
ActionButtonの指定
ActionButtonは幾つかの種類があります。EditTextの”android:imeOptions”属性にタイプ名を指定して選びます。
<EditText android:id="@+id/edtDone" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" android:imeOptions="actionDone" android:inputType="textPersonName" android:text="Action Done" />
ActionButtonを押下すると、ボタンに対応したActionIdが取得できるので、それによりどのボタンが押下されたのかを判別できる仕組みになっています。
imeOptions | アイコン | actionId | コメント |
---|---|---|---|
normal | actionUnspecifiedと同じ | ||
actionNone | 値は無い | テキストフィールドに改行(0x0a)を挿入 | |
actionDone | IME_ACTION_DONE | ||
actionNext | IME_ACTION_NEXT | ||
actionPrevious | IME_ACTION_PREVIOUS | ||
actionGo | IME_ACTION_GO | ||
actionSearch | IME_ACTION_SEARCH | ||
actionSend | IME_ACTION_SEND | ||
actionUnspecified | IME_ACTION_NEXT | 自分より下にEditTextがある時 | |
IME_ACTION_DONE | 自分より下にEditTextがない時 |
ただし、actionUnspecifiedだけ少し特殊です。
TextView.java#onCreateInputConnection()を参照すると、actionUnspecifiedはactionNextまたはDoneに書き換えられるようです。なので、actionNextまたはDoneのような振舞いになります。
@Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { if (onCheckIsTextEditor() && isEnabled()) { ... if (focusSearch(FOCUS_DOWN) != null) { outAttrs.imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_NEXT; } if (focusSearch(FOCUS_UP) != null) { outAttrs.imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS; } if ((outAttrs.imeOptions & EditorInfo.IME_MASK_ACTION) == EditorInfo.IME_ACTION_UNSPECIFIED) { if ((outAttrs.imeOptions & EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0) { // An action has not been set, but the enter key will move to // the next focus, so set the action to that. outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT; } else { // An action has not been set, and there is no focus to move // to, so let's just supply a "done" action. outAttrs.imeOptions |= EditorInfo.IME_ACTION_DONE; } if (!shouldAdvanceFocusOnEnter()) { outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_ENTER_ACTION; } } ... } return null; }
※focusSearch(FOCUS_DOWN)は自分よりも下にEditTextがある場合にそのViewを返し、無い場合にNullを返します。
ActionButtonのイベント
デフォルトの処理
ActionButtonを押下するとActionIdが取得できるので、ボタンに対応した処理を行うことが出来ます。次の3つはデフォルトで処理が定義されています。
アイコン | actionId | 処理 |
---|---|---|
IME_ACTION_DONE | SWキーボードを閉じる | |
IME_ACTION_NEXT | 自分よりも下のEditTextへフォーカスを移動し、 SWキーボードからの入力を待つ |
|
IME_ACTION_PREVIOUS | 自分よりも上のEditTextへフォーカスを移動し、 SWキーボードからの入力を待つ |
TextView.java#onEditorAction()を参照すると、デフォルトの処理が記述されています。
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 = getInputMethodManager(); if (imm != null && imm.isActive(this)) { imm.hideSoftInputFromWindow(getWindowToken(), 0); } return; } } ... }
リスナーの登録
ActionButtonを押下するとActionIdが取得できるので、ボタンに対応した処理をリスナーを通してユーザ側で定義することが出来ます。
定義はTextView.OnEditorActionListenerインターフェイスを実装してExitTextへ設定します。
先に述べた「デフォルトの処理」は上書きされて動作しなくなるので注意してください。
override fun onCreate(savedInstanceState: Bundle?) { ... findViewById<EditText>(R.id.editText) .setOnEditorActionListener(editorAction) } private val editorAction: TextView.OnEditorActionListener = object: TextView.OnEditorActionListener { override fun onEditorAction(v: TextView, actionId: Int, event: KeyEvent?): Boolean { return if(actionId == EditorInfo.IME_ACTION_DONE) { // ActionButton押下後の処理 true } else if(event != null && event.keyCode == KeyEvent.KEYCODE_ENTER) { // Enter押下後の処理 true } else false } }