You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何实现点击屏幕其他区域时清除TextInputEditText的焦点

如何实现点击屏幕其他区域时清除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失去焦点~

选一个适合你布局的方案试试吧,我自己平时用方案二最多,省心又好用😉

火山引擎 最新活动