Android Studio 自定义Dialog内RecyclerView中EditText失焦问题
问题:Dialog嵌套RecyclerView中EditText输入单字符后自动失焦
- 开发场景:Android Studio开发环境下,自定义Dialog中嵌套RecyclerView,RecyclerView条目内包含EditText控件
- 异常表现:点击EditText后仅能输入1个字符,控件就会自动丢失输入焦点
- 排查背景:普通RecyclerView直接嵌套EditText的同类解决方案在当前场景下全部无效,问题触发核心是双层嵌套结构(RecyclerView位于自定义Dialog内部)
附1:自定义Dialog布局代码(包含嵌套的RecyclerView)
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:foregroundTint="#009688"> <androidx.cardview.widget.CardView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <EditText android:id="@+id/nombreGasto" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" android:hint="Nombre" android:inputType="textPersonName" android:minHeight="48dp" /> <EditText android:id="@+id/precioGasto" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" android:hint="Precio" android:inputType="numberDecimal" android:minHeight="48dp" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerGasto" android:layout_width="match_parent" android:layout_height="145dp" /> <Space android:layout_width="match_parent" android:layout_height="10dp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/cancelButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:backgroundTint="#FFFFFF" android:text="Cancel" android:textColor="#00BCD4" /> <Button android:id="@+id/addButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:backgroundTint="#FFFFFF" android:text="OK" android:textColor="#00BCD4" /> </LinearLayout> </LinearLayout> </androidx.cardview.widget.CardView> </androidx.constraintlayout.widget.ConstraintLayout>
附2:RecyclerView条目布局代码(包含触发异常的EditText)
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content"> <androidx.cardview.widget.CardView android:layout_width="0dp" android:layout_height="50dp" android:layout_marginStart="8dp" android:layout_marginEnd="8dp" android:orientation="horizontal" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <LinearLayout android:id="@+id/linearLay" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <TextView android:id="@+id/personNamePrecio" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" android:text="PersonaX" android:textAlignment="viewStart" android:textSize="24sp" android:textStyle="bold" /> <EditText android:id="@+id/editTextPrecioPersona" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:ems="10" android:hint="0.00" android:inputType="numberDecimal" android:minHeight="48dp" /> </LinearLayout> </androidx.cardview.widget.CardView> </androidx.constraintlayout.widget.ConstraintLayout>
解决方案
问题核心原因:EditText输入内容后触发RecyclerView全局重绘,Dialog窗口焦点处理逻辑和RecyclerView焦点复用逻辑冲突,导致每次文本变更后控件被重新布局、焦点被回收。按以下步骤修改即可修复:
- 调整RecyclerView基础配置
在Dialog初始化代码中找到RecyclerView实例,添加以下配置,禁用布局时的焦点自动回收:
Java代码对应写法:recyclerGasto.apply { // 禁用子视图变化触发的全局焦点重新分配 isFocusableInTouchMode = false // 子控件优先获取焦点,父布局不抢占 descendantFocusability = ViewGroup.FOCUS_AFTER_DESCENDANTS // 固定RecyclerView高度,避免输入时高度变化触发全量重绘 setHasFixedSize(true) }RecyclerView recyclerGasto = findViewById(R.id.recyclerGasto); recyclerGasto.setFocusableInTouchMode(false); recyclerGasto.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); recyclerGasto.setHasFixedSize(true); - 修正适配器文本监听逻辑
禁止在onBindViewHolder中给EditText设置「文本变化就直接更新数据源、调用notifyDataSetChanged()」的逻辑,这会触发整个列表重绘,直接夺走输入焦点。正确逻辑:- 给EditText绑定
OnFocusChangeListener,只有控件失去焦点时,才把输入内容同步到对应位置的数据源 - 如果需要实时同步,用
notifyItemChanged(adapterPosition, payload)做局部更新,不要调用全量刷新的notifyDataSetChanged()
参考写法:
override fun onBindViewHolder(holder: ViewHolder, position: Int) { val itemData = dataList[position] // 先移除旧的文本监听,避免视图复用触发逻辑错乱 holder.editText.removeTextChangedListener(holder.textWatcher) // 填充已保存文本,不要每次绑定都重置光标位置 if (holder.editText.text.toString() != itemData.precio) { holder.editText.setText(itemData.precio) } // 失焦时再同步数据到数据源 holder.editText.onFocusChangeListener = View.OnFocusChangeListener { v, hasFocus -> if (!hasFocus) { val input = (v as EditText).text.toString() dataList[position].precio = input } } } - 给EditText绑定
- 补充Dialog窗口配置
在自定义Dialog的onCreate方法中添加窗口软键盘配置,避免弹窗默认焦点拦截逻辑干扰输入:window?.apply { clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) clearFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) } - 补全条目布局焦点属性
给条目布局里的editTextPrecioPersona添加两个属性,避免布局重排时焦点丢失:<EditText android:id="@+id/editTextPrecioPersona" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:ems="10" android:hint="0.00" android:inputType="numberDecimal" android:minHeight="48dp" android:focusable="true" android:focusableInTouchMode="true" />
注意:如果适配器里给EditText设置了
setOnClickListener,不要在点击事件里调用任何刷新列表的方法,否则点击时就会触发重绘夺走焦点。
内容的提问来源于stack exchange,提问作者Adrián Mon Maroto
相关产品推荐
相关产品推荐

