画面側
<!-- 背景がフォーカスされる用の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
にしておきます。
さらに、focusable
とfocusableInTouchMode
はtrue
にしておきます。
これで、タッチモードによらずフォーカスが当たるようになります。
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)
}
editText
のsetOnFocusChangeListener
でフォーカスが外れたときにキーボードを非表示にする処理を実行するようリスナーを設定します。
setOnFocusChangeListener
は、フォーカスを取得したり消失したりした時にリスナーが実行されるためフォーカスが外れたときだけキーボードを非表示にするようにしています。
dispatchTouchEvent
では、focusView
にフォーカスを強制的に当てるようにrequestFocus
を実行しています。
これがないと背景をタップしてもフォーカスが移動せずキーボードが表示されたままになってしまいます。
dispatchTouchEvent
は、タップイベントが起こった時に実行されます。onTouchEvent
だと、レイアウトによっては子でタッチイベントの伝搬が終了してしまい親でonTouchEvent
が実行されないことがあるため必ず実行されるdispatchTouchEvent
にしました。
dispatchTouchEvent
とonTouchEvent
について、詳しくは、Android のタッチイベントを理解する(その1) - Unmotivatedが参考になります。
起動した時の挙動
起動した時は、editText
にフォーカスは当たりません。
focusView
でfocusable
とfocusableInTouchMode
をtrue
にしているため、起動時にはfocusView
にフォーカスが当たります。
editText
にフォーカスした状態でキーボードを非表示にするために、AndroidManifest.xml
にwindowSoftInputMode
を指定してもfocusView
にフォーカスが当たってしまい上手くいかないようです。
AndroidアプリのEditTextを含む画面でキーボードを非表示にする - Qiitaの「EditTextからフォーカスをはずす」が今回の対応にあたります。
参考
[Android]画面タップでキーボードを閉じる - ワークレ
入力イベントの概要 | Android デベロッパー | Android Developers
表示| Androidデベロッパー| Android開発者