so my problem may sound a little bit weird but let me explain. I have custom recycle view adapter and custom layout. In custom layout I have buttons which increment or decrement TextView Value. But when I press 1 button it increments like 4 others.
As you can see here I only clicked delay and defendant but house and item incremented too. Here's my code
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
var pName : TextView = holder.itemView.findViewById(R.id.ingredientName)
val ingrCount : TextView = holder.itemView.findViewById(R.id.ingredientCount)
val decrementIngr : Button = holder.itemView.findViewById(R.id.deleteIngeredient)
val incrementIngr : Button = holder.itemView.findViewById(R.id.addIngredient)
pName.text = ingredients[position]
incrementIngr.setOnClickListener{
val count = Integer.parseInt(ingrCount.text.toString()) 1
ingrCount.text = "$count"
}
decrementIngr.setOnClickListener{
if(Integer.parseInt(ingrCount.text.toString()) - 1 > 0)
{
val count = Integer.parseInt(ingrCount.text.toString()) - 1
ingrCount.text = "$count"
}
}
}
CodePudding user response:
The problem is that you are saving your ingrCount
state for each item directly on the TextView.text property. Since this is inside a RecyclerView the Views (your custom layouts) get reused (recycled). There are only enough of them created to cover a bit more than the height of your RecyclerView, but as you scroll further the same views are reused. That is why you see your other numbers repeat.
Your click handlers have never incremented or decremented more than a single TextView per click.
Inside override fun onBindViewHolder(holder: ViewHolder, position: Int)
you always have to (re)set all parts of the UI that you want to be bound to your underlying data. In your current code you only set the pName.text
, this is why that one works correctly. Do the same for the ingrCount.text
and it will work as you expect.
You can place a breakpoint or some logging output (log the position parameter for example) inside onBindViewHolder
and you will see when different positions are rebound as you scroll up and down the list. This will give you a better understanding on how the RecyclerView works.
EDIT: You need to keep the ingredients count information the same as you do with ingredient names.
How you do it is up to you, you could store (data) classes instead of just ingredient names inside your ingredients Array/ArrayList.
So something like this
class Ingredient(val name: String, var count: Int = 0) {}
Or you could keep the ingredient counts in a separate Array/ArrayList/Map.
Let's say that you would use the class Ingredient
to model your data, then your code inside onBindViewHolder
would change to
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
var pName : TextView = holder.itemView.findViewById(R.id.ingredientName)
val ingrCount : TextView = holder.itemView.findViewById(R.id.ingredientCount)
val decrementIngr : Button = holder.itemView.findViewById(R.id.deleteIngeredient)
val incrementIngr : Button = holder.itemView.findViewById(R.id.addIngredient)
val ingredient = ingredients[position]
pName.text = ingredient.name
ingrCount.text = ingredient.count.toString()
incrementIngr.setOnClickListener{
ingredient.count = 1
ingrCount.text = ingredient.count.toString()
}
decrementIngr.setOnClickListener{
if(ingredient.count > 0)
{
ingredient.count -= 1
ingrCount.text = ingredient.count.toString()
}
}
}