EditTextのActionButtonで入力の完了を通知

投稿日:  更新日:

EditTextのActionButtonで入力の完了を通知する方法を紹介します。

スポンサーリンク

ActionButtonとは

EditTextは入力デバイス(インプットメソッド、具体的にはキーボードなど)から入力されたテキストを取得するウィジェットです。

EditTextへ入力されたテキストを確定する際に、HWキーボードではEnterキーを押下したりします。

SWキーボードでも同様ですが、さらにEnterキーの代わりにActionButtonを定義できるようになっていて、入力の完了を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コメント
normalActionButton_NormalactionUnspecifiedと同じ
ActionButton_Done
actionNoneActionButton_None値は無いテキストフィールドに改行(0x0a)を挿入
actionDoneActionButton_DoneIME_ACTION_DONE
actionNextActionButton_NextIME_ACTION_NEXT
actionPreviousActionButton_PreviousIME_ACTION_PREVIOUS
actionGoActionButton_GoIME_ACTION_GO
actionSearchActionButton_SearchIME_ACTION_SEARCH
actionSendActionButton_SendIME_ACTION_SEND
actionUnspecifiedActionButton_UnspecifiedIME_ACTION_NEXT自分より下にEditTextがある時
ActionButton_DoneIME_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処理
ActionButton_DoneIME_ACTION_DONESWキーボードを閉じる
ActionButton_NextIME_ACTION_NEXT自分よりも下のEditTextへフォーカスを移動し、
SWキーボードからの入力を待つ
ActionButton_PreviousIME_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
        }
    }
スポンサーリンク
スポンサーリンク