ViewHolder 点击会扰乱其他视图

ViewHolder click is messing other views

我有以下 RecyclerView.Adapter:

class SpeciesAdapter(val activity: Activity, private val species: ArrayList<Specie>) : RecyclerView.Adapter<SpeciesAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, position: Int): ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        return ViewHolder(inflater.inflate(R.layout.specie_item, parent, false))
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val specie = species[position]
        holder.specie.text = specie.name
        holder.header.setOnClickListener {
            if (holder.information.visibility == View.GONE) showInformation(holder)
            else hideInformation(holder)
        }
    }

    private fun showInformation(holder: ViewHolder) {
        holder.information.visibility = View.VISIBLE
        holder.arrow.rotation = -90f
    }

    private fun hideInformation(holder: ViewHolder) {
        holder.information.visibility = View.GONE
        holder.arrow.rotation = 90f
    }

    override fun getItemCount() = species.size

    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val header: RelativeLayout = view.header_layout
        val arrow: ImageView = view.arrow_image
        val specie: TextView = view.specie_text
        val information: LinearLayout = view.information_layout
    }
}

并且正在制作这个:

https://media.giphy.com/media/9JcLhfgXOdt81WUxsE/giphy.mp4

如您所见,如果我单击某个项目,则会打开一个带有加载项的布局。我的问题是,当我单击一个项目然后滚动时,其他一些项目也会打开,但我没有单击它们。就像 ViewHolder 正在回收视图并且不关心带有加载栏的布局应该是不可见的。

我的适配器可能出了什么问题?

好的,你要明白的是ViewHolder是一个View,它可以在给定的时间代表任何Specie对象。当有一些滚动时,这个 ViewHolder 被 RecyclerView 重用并绑定到其他 Specie 对象,试图加载最少数量的视图(这就是它被称为 "Recycler" 的原因)。

如果您只是更改一个 Specie 物品的持有人的 属性,当持有人被重新用于显示另一个 Specie 对象时,如果您不这样做,属性 将保持不变 "reset"它。

简而言之,您必须在绑定方法中设置所有 ViewHolder 属性,以确保持有人现在正确地表示将要显示的 Specie 对象。

也就是说,你要做的,例如,是保留一个列表或地图或你想知道什么 Specie 对象是什么 "expanded" 在给定的时间,当 bind 方法是调用,检查是否必须扩展特定的 Specie 对象,并根据它显示持有者扩展信息。


编辑问题的解决方案:

class SpeciesAdapter(val activity: Activity, private val species: ArrayList<Specie>) : RecyclerView.Adapter<SpeciesAdapter.ViewHolder>() {

    // added an ArrayList to store the opened species
    private val opened = arrayListOf<Specie>()

    // ...

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val specie = species[position]

        // added a condition to check if a specie was opened
        // and updates according to the result
        if (opened.contains(specie)) showInformation(holder, specie)
        else hideInformation(holder, specie)

        holder.specie.text = specie.name
        holder.header.setOnClickListener {
            if (holder.information.visibility == View.GONE) showInformation(holder, specie)
            else hideInformation(holder, specie)
        }
    }

    private fun showInformation(holder: ViewHolder, specie: Specie) {
        holder.information.visibility = View.VISIBLE
        holder.arrow.rotation = -90f

        // checking if is opened to avoid duplicates
        if (!opened.contains(specie)) opened.add(specie)
    }

    private fun hideInformation(holder: ViewHolder, specie: Specie) {
        holder.information.visibility = View.GONE
        holder.arrow.rotation = 90f

        // checking if exists to avoid crashes
        if (opened.contains(specie)) opened.remove(specie)
    }

    // ...
}