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)
}
// ...
}
我有以下 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)
}
// ...
}