如何实现点击屏幕其他区域时清除TextInputEditText的焦点
我来帮你搞定这个问题!之前我也踩过类似的坑——直接给父布局调用clearFocus()根本没用,因为默认情况下ConstraintLayout、LinearLayout这些布局是不能获取焦点的,所以它们没法“抢”走EditText的焦点。下面给你分享几个亲测好用的解决方案,你可以根据自己的布局情况选:
方案一:让根布局可聚焦,点击时主动清除EditText焦点
这个方法最直接,适合布局结构不复杂的情况:
步骤1:修改根布局的XML属性
给你的根布局(比如ConstraintLayout)加上这两个属性,让它能接收焦点:
<androidx.constraintlayout.widget.ConstraintLayout <!-- 其他原有属性 --> android:focusable="true" android:focusableInTouchMode="true"> <!-- 你的TextInputLayout和其他控件 --> </androidx.constraintlayout.widget.ConstraintLayout>
步骤2:给根布局设置点击监听
先给你的TextInputEditText加个id(比如mode_name_edit),然后在Activity/Fragment里给根布局加点击事件,点击时让EditText主动失去焦点:
Kotlin代码:
val rootLayout = findViewById<ConstraintLayout>(R.id.rootLayout) val editText = findViewById<TextInputEditText>(R.id.mode_name_edit) rootLayout.setOnClickListener { editText.clearFocus() // 要是顺便想隐藏软键盘,就加下面这两行 val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager imm.hideSoftInputFromWindow(editText.windowToken, 0) }
Java代码:
ConstraintLayout rootLayout = findViewById(R.id.rootLayout); TextInputEditText editText = findViewById(R.id.mode_name_edit); rootLayout.setOnClickListener(v -> { editText.clearFocus(); // 隐藏软键盘的代码 InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); });
方案二:自定义根布局(一次定义,全局复用)
如果你的布局里有ScrollView、RecyclerView这类会拦截触摸事件的控件,方案一可能会失效,这时候自定义根布局是更靠谱的选择:
步骤1:创建自定义布局类
比如我们自定义一个ConstraintLayout,重写触摸事件分发逻辑,判断点击区域是不是在EditText外面:
class FocusClearConstraintLayout @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : ConstraintLayout(context, attrs, defStyleAttr) { override fun dispatchTouchEvent(ev: MotionEvent): Boolean { if (ev.action == MotionEvent.ACTION_DOWN) { // 获取当前拥有焦点的View val focusedView = currentFocus if (focusedView is TextInputEditText) { val editTextRect = Rect() focusedView.getGlobalVisibleRect(editTextRect) // 判断点击的坐标是不是在EditText的范围外 if (!editTextRect.contains(ev.rawX.toInt(), ev.rawY.toInt())) { focusedView.clearFocus() // 顺便隐藏软键盘 val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager imm.hideSoftInputFromWindow(focusedView.windowToken, 0) } } } return super.dispatchTouchEvent(ev) } }
步骤2:在XML里使用自定义布局
把原来的根布局替换成你自定义的这个类(注意替换成你自己的包名):
<com.yourpackage.FocusClearConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 你的TextInputLayout和其他控件 --> </com.yourpackage.FocusClearConstraintLayout>
这个方案的好处是一劳永逸,以后所有需要这个功能的页面都能用这个自定义布局,不用重复写代码。
方案三:Activity全局处理(适合全页面生效)
如果你的整个Activity里所有EditText都需要这个效果,直接在Activity里重写onTouchEvent就行:
override fun onTouchEvent(event: MotionEvent): Boolean { if (event.action == MotionEvent.ACTION_DOWN) { val focusedView = currentFocus if (focusedView is TextInputEditText) { val editTextRect = Rect() focusedView.getGlobalVisibleRect(editTextRect) if (!editTextRect.contains(event.rawX.toInt(), event.rawY.toInt())) { focusedView.clearFocus() val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager imm.hideSoftInputFromWindow(focusedView.windowToken, 0) } } } return super.onTouchEvent(event) }
最后补个小提醒
你之前调用父布局clearFocus()没用的原因,是因为父布局默认不支持获取焦点,所以它的clearFocus()不会影响子View的焦点状态。必须让EditText主动调用clearFocus(),或者让一个能获取焦点的View去“抢”焦点(比如让根布局requestFocus())才能让EditText失去焦点~
选一个适合你布局的方案试试吧,我自己平时用方案二最多,省心又好用😉




