EditText以外のタップでキーボードを閉じたい
プラットフォームに関係なく、よくある要件ですね!
色々調べたのですが下記のようにしたら大体のレイアウトでカバーできそうだなって思ったので共有します
dispatchTouchEvent() を使う
onTouchEvent()
を使う記事などが多くありますが、List系のレイアウトがあったりScrollViewが入ってると反応しないので dispatchTouchEvent()
を使っておけばいいと思います。
あとは、スクロールのタッチアクションにも反応してしまうので、そこも対応が必要です。
タッチした箇所がEditTextだった場合は処理をしたくないので、タッチ領域がEditTextの表示領域かを判定する必要があります
private var lastEventAction: Int? = null
override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
// スクロール時のタップを無視させる
if (lastEventAction != MotionEvent.ACTION_MOVE && event?.action == MotionEvent.ACTION_UP) {
// タップ位置がEditText以外だったらフォーカス外す
if (!isEditTextTouch(event.rawX.toInt(), event.rawY.toInt(), editText1, editText2, editText3)) {
// 画面内のルート要素とかをフォーカスさせる
}
}
lastEventAction = event?.action
return super.dispatchTouchEvent(event)
}
private fun isEditTextTouch(touchRawX: Int, touchRawY: Int, vararg editText: EditText): Boolean {
return editText.any {
val areaOutsideFocusedView = Rect()
it.getGlobalVisibleRect(areaOutsideFocusedView)
// 対象のEditTextの表示領域内のタップであるか判定
return@any areaOutsideFocusedView.contains(touchRawX, touchRawY)
}
}
おそらくこれで大体の画面レイアウトで対応が可能かと思います。
おまけ
キーボード閉じる処理
fun Context.hideKeyboard(view: View) {
getSystemService<InputMethodManager>()?.let {
it.hideSoftInputFromWindow(view.windowToken, 0)
view.clearFocus()
}
}
こちらは自作ライブラリでも同様の処理を用意しております