3
3

More than 3 years have passed since last update.

[Android][Kotlin]背景をタップしてキーボードを非表示にする

Posted at

画面側

    <!-- 背景がフォーカスされる用のTextView -->
    <TextView
        android:id="@+id/focusView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:focusable="true"
        android:focusableInTouchMode="true"
        app:layout_constraintBottom_toTopOf="parent"
        app:layout_constraintEnd_toStartOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@+id/editText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="10"
        android:inputType="text"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

EditText以外にLayoutに背景をタップした時に背景がフォーカスされるためにTextViewを追加します。
このTextViewは、実際に画面に表示する訳ではないため幅と高さは0dpにしておきます。

さらに、focusablefocusableInTouchModetrueにしておきます。
これで、タッチモードによらずフォーカスが当たるようになります。

Activity側

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        editText.setOnFocusChangeListener { v, hasFocus ->
            if (!hasFocus) {
                val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                imm.hideSoftInputFromWindow(v.windowToken, 0)
            }
        }
    }

    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        focusView.requestFocus()
        return super.dispatchTouchEvent(ev)
    }

editTextsetOnFocusChangeListenerでフォーカスが外れたときにキーボードを非表示にする処理を実行するようリスナーを設定します。
setOnFocusChangeListenerは、フォーカスを取得したり消失したりした時にリスナーが実行されるためフォーカスが外れたときだけキーボードを非表示にするようにしています。

dispatchTouchEventでは、focusViewにフォーカスを強制的に当てるようにrequestFocusを実行しています。
これがないと背景をタップしてもフォーカスが移動せずキーボードが表示されたままになってしまいます。
dispatchTouchEventは、タップイベントが起こった時に実行されます。onTouchEventだと、レイアウトによっては子でタッチイベントの伝搬が終了してしまい親でonTouchEventが実行されないことがあるため必ず実行されるdispatchTouchEventにしました。
dispatchTouchEventonTouchEventについて、詳しくは、Android のタッチイベントを理解する(その1) - Unmotivatedが参考になります。

起動した時の挙動

起動した時は、editTextにフォーカスは当たりません。
focusViewfocusablefocusableInTouchModetrueにしているため、起動時にはfocusViewにフォーカスが当たります。

editTextにフォーカスした状態でキーボードを非表示にするために、AndroidManifest.xmlwindowSoftInputModeを指定してもfocusViewにフォーカスが当たってしまい上手くいかないようです。
AndroidアプリのEditTextを含む画面でキーボードを非表示にする - Qiitaの「EditTextからフォーカスをはずす」が今回の対応にあたります。

参考

[Android]画面タップでキーボードを閉じる - ワークレ

入力イベントの概要  |  Android デベロッパー  |  Android Developers

表示| Androidデベロッパー| Android開発者

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3