RecyclerView中复用EditText问题

615 阅读2分钟

1. 焦点问题

原因

当滑动RecyclerView时,EditText的焦点可能会混乱。这个问题通常发生在视图回收和重用时。

解决方法

在RecyclerView中使用EditText时,会出现焦点错乱问题。需要监听焦点变化,并在RecyclerView滑动时重新请求焦点。解决方案如下:

class EditTextAdapter : RecyclerView.Adapter<EditorViewHolder>() {

    // 记录获取焦点的EditText的索引值
    private var mFocusEditIndex: Int = -1

    override fun onBindViewHolder(holder: EditorViewHolder, position: Int) {
        val editText = holder.mEditText

        // 监听焦点获取
        editText?.setOnFocusChangeListener { _, hasFocus ->
            if (hasFocus) {
                // 记录获取焦点的EditText的索引值
                mFocusEditIndex = holder.bindingAdapterPosition
                // 设置EditText光标位置
                editText.setSelection(editText.text.length)
            }
        }

        // 如果当前EditText是记录的获取了焦点的EditText
        if (mFocusEditIndex == position) {
            // EditText请求获取焦点
            editText?.requestFocus()
        }
    }

    override fun onViewAttachedToWindow(holder: EditorViewHolder) {
        super.onViewAttachedToWindow(holder)
        if (mFocusEditIndex == holder.bindingAdapterPosition) {
            holder.mEditText?.requestFocus()
        }
    }

    override fun onViewDetachedFromWindow(holder: EditorViewHolder) {
        super.onViewDetachedFromWindow(holder)
        holder.mEditText?.clearFocus()
    }
}

2. 文本错乱问题

原因

由于视图回收,EditText可能会显示错误的数据或文本。需要确保正确地将数据绑定到视图,并在必要时清除旧的文本或数据。

解决方式一:为EditText设置TextWatcher监听

在ViewHolder创建时,为EditText设置TextWatcher监听,使EditText和TextWatcher一一对应。

解决方式二:监听EditText焦点变化

当EditText获取焦点时,添加TextWatcher;失去焦点时,移除TextWatcher。

override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
    val editText = holder.mEditText

    val mWatcher = object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}

        override fun afterTextChanged(s: Editable?) {
            // 保存EditText的内容
            val newText = s.toString()
            // 更新对应的数据项
            data[position].text = newText
        }
    }

    editText?.setOnFocusChangeListener { _, hasFocus ->
        if (hasFocus) {
            editText.addTextChangedListener(mWatcher)
        } else {
            editText.removeTextChangedListener(mWatcher)
        }
    }
}

相关文章:Recyclerview EditText 引发的问题与解决方案

3. 无法选中文本

原因

有时,在复用EditText后,可能会出现文本不可选中的情况。这通常与EditText的焦点处理有关。

解决方式一:重写EditText的onAttachedToWindowsetEnabled方法

public class SelectableEditText extends AppCompatEditText {

    private boolean mEnabled;

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        try {
            if (!mEnabled) return;
            super.setEnabled(false);
            super.setEnabled(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void setEnabled(boolean enabled) {
        this.mEnabled = enabled;
        super.setEnabled(enabled);
    }
}

onBindViewHolder方法中调用:

override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
    viewHolder.mEditText?.apply {
        isEnabled = false
        isEnabled = true
    }
}

解决方式二:设置setTextIsSelectable

override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
    viewHolder.mEditText?.fixTextSelection()
}

fun TextView.fixTextSelection() {
    setTextIsSelectable(false)
    post { setTextIsSelectable(true) }
}

解决方式三:调用measure方法

override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
    viewHolder.mEditText?.apply {
        measure(-1, -1)
        setTextIsSelectable(true)
    }
}

相关文章: