📝
Android キーボードを隠す
Fragmentでタッチイベントを使ってキーボードを隠す方法
はじめに
ChatGPT先生に聞いてみました。
この記事では、ChatGPTを活用して得られたアイデアを元に、Fragment
でのタッチイベントを使ったキーボード制御の実装方法をご紹介します。
背景
EditText
にフォーカスがある状態で他の部分をタップすると、キーボードを隠したい場面は多くのアプリで必要になります。
この記事では、Fragment
を用いて、EditText
以外をタップした場合にキーボードを隠す汎用的な方法をご紹介します。
解決策
ルートビュー
とすべてのViewGroup
にsetOnTouchListener
を設定し、タッチイベントを検知してキーボードを隠す処理を実現しています。(複数回処理されます。)
自分はベースのフラグメントとして用意するFragment
に実装して、それを継承して処理します。
実装例
@SuppressLint("ClickableViewAccessibility")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
/** ビュー階層を再帰的に探索 */
fun traverseViews(view: View, callback: (View) -> Unit) {
callback.invoke(view)
if (view is ViewGroup) {
for (i in 0 until view.childCount) {
traverseViews(view.getChildAt(i), callback)
}
}
}
// 対象ビューにsetOnTouchListenerを設定
traverseViews(view) { currentView ->
currentView.setOnTouchListener { _, event ->
processTouchEvent(event, view)
false // デフォルトのタッチ動作を保持
}
}
}
private fun processTouchEvent(event: MotionEvent, rootView: View) {
fun findViewAt(view: View, x: Int, y: Int): View? {
if (view !is ViewGroup) {
if (x >= view.left && x <= view.right && y >= view.top && y <= view.bottom) {
return view
}
return null
}
for (i in 0 until view.childCount) {
val child = view.getChildAt(i)
val foundView = findViewAt(child, x - child.left, y - child.top)
if (foundView != null) {
return foundView
}
}
return view // 必要に応じてコンテナビューを返す
}
fun findTouchedView(rootView: View, event: MotionEvent): View? {
val location = IntArray(2)
rootView.getLocationOnScreen(location)
val x = event.rawX.toInt() - location[0]
val y = event.rawY.toInt() - location[1]
return findViewAt(rootView, x, y)
}
if (event.action == MotionEvent.ACTION_DOWN) {
findTouchedView(rootView, event)?.let { touchedView ->
if (touchedView !is EditText) {
dismissKeyboard(touchedView)
}
}
}
}
// キーボードを閉じる
private fun dismissKeyboard(view: View) {
ContextCompat.getSystemService(view.context, InputMethodManager::class.java)?.let { imm ->
imm.hideSoftInputFromWindow(view.windowToken, 0)
}
}
Discussion