Bootstrap

Android RecyclerView列表中存在Checkbox错乱以及滑动更新Checkbox状态解决方案

在Android开发中有时候在RecyclerView中使用Checkbox进行选中操作:

当我们选中第一个,然后滑动列表发现下面同样有一个也是被选中的,但是其实我们没有去选择,这是因为RecyclerView的复用item布局导致的。为了解决这个问题,通常会把当前选择的位置存储在一个Boolean类型的数组中,或者存储在Model中的一个字段中也是可以的:

// 数据源
private var mList: List<String> = list
// 存储选中的item
private var mEllipsis = hashMapOf<Int, Boolean>()

override fun onCreateViewHolder(p0: ViewGroup, p1: Int): ListAdapter.ListViewHolder {
    var view = LayoutInflater.from(p0.context).inflate(R.layout.view_reyclerview_item_layout, p0, false)
    return ListAdapter.ListViewHolder(view, itemClick)
}

override fun getItemCount(): Int {
    return mList.size
}

override fun onBindViewHolder(holder: ListAdapter.ListViewHolder, position: Int) {
	// 判断是否已经选中
	holder.itemView.cb_check.isChecked = mEllipsis.containsKey(position)

    holder.itemView.cb_check.setOnCheckedChangeListener { buttonView, isChecked ->
    	// 选中存储,否则删除
        if (isChecked) {
            mEllipsis[position] = true
        } else {
            mEllipsis.remove(position)
        }
    }
}

这样就解决了错乱的问题。但是另一个问题也伴随产生:当我们选择第一个然后滑动底部,再次滑动到顶部的时候发现选中的第一个已经未选中状态了。

debug发现当我们往下滑动一段距离之后CheckboxsetOnCheckedChangeListener方法会被调用,然后isChecked = false,这样就把第一个从数组中删除了,导致回到顶部是未选中的状态。个人觉得是RecyclerView复用第一个布局的时候,当前的这个item是未选中,然后就直接修改了Checkbox的选中状态为false

解决方案:
第一种:在holder.itemView.cb_check.isChecked = mEllipsis.containsKey(position)之前先给CheckboxsetOnCheckedChangeListener设置为null。具体代码:

override fun onBindViewHolder(holder: ListAdapter.ListViewHolder, position: Int) {
	// 先设置为null
    holder.itemView.cb_check.setOnCheckedChangeListener(null)
	// 判断是否已经选中
    holder.itemView.cb_check.isChecked = mEllipsis.containsKey(position)

    holder.itemView.cb_check.setOnCheckedChangeListener { buttonView, isChecked ->
    	// 选中存储,否则删除
        if (isChecked) {
            mEllipsis[position] = true
        } else {
            mEllipsis.remove(position)
        }
    }
}

第二种:由于往下滑动导致isChecked = false是系统所为,而非人为点击,所以在CheckboxsetOnCheckedChangeListener方法中判断一下是不是点击导致的状态改变,也是可以解决的:

holder.itemView.cb_check.setOnCheckedChangeListener { buttonView, isChecked ->
	// 判断是不是人为点击
    if (buttonView.isPressed) {
    	// 选中存储,否则删除
        if (isChecked) {
            mEllipsis[position] = true
        } else {
            mEllipsis.remove(position)
        }
    }
}

第三种:
CheckboxsetOnCheckedChangeListener改为setOnClickListener

holder.itemView.cb_check.setOnClickListener {
    if (holder.itemView.cb_check.isChecked) {
        mEllipsis[position] = true
    } else {
        mEllipsis.remove(position)
    }
}

第四种:
Checkbox换成ImageView
方法和第三种一样,只不过更换个控件。

参考文档

;