I am trying to change first text(position = 0) gravity from List in 'onBindViewHolder(viewHolder: ViewHolder, position: Int)', but, except for the first, the gravity of some elements changes. Could you tell me where this problem comes from?
You can see code below and also logs
class ButtonsListAdapter(private val dataSet: List<String>) :
RecyclerView.Adapter<ButtonsListAdapter.ViewHolder>() {
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView
val divider: View
init {
textView = view.findViewById(R.id.textView)
divider = view.findViewById(R.id.divider)
}
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.buttons_list_item, viewGroup, false)
return ViewHolder(view)
}
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
viewHolder.textView.text = dataSet[position]
if(position == 0) {
Log.i("Position", " position -> $position ")
viewHolder.textView.gravity = Gravity.START or Gravity.CENTER_VERTICAL
}
Log.i("Position", " gravity -> $position " viewHolder.textView.gravity)
}
override fun getItemCount() = dataSet.size
}
Logs
I/Position: position -> 0
I/Position: gravity -> 0 8388627
I/Position: gravity -> 1 17
I/Position: gravity -> 2 17
I/Position: gravity -> 3 17
I/Position: gravity -> 4 17
I/Position: gravity -> 5 17
I/Position: gravity -> 6 17
I/Position: gravity -> 7 17
I/Position: gravity -> 8 17
I/Position: gravity -> 9 8388627
I/Position: gravity -> 10 17
I/Position: gravity -> 11 17
I/Position: gravity -> 12 17
I/Position: gravity -> 13 17
I/Position: gravity -> 14 17
I/Position: gravity -> 15 17
I/Position: gravity -> 16 17
I/Position: gravity -> 17 17
I/Position: gravity -> 9 8388627
I/Position: gravity -> 8 17
I/Position: gravity -> 7 17
I/Position: gravity -> 6 17
I/Position: gravity -> 5 17
I/Position: gravity -> 4 17
I/Position: gravity -> 3 17
I/Position: gravity -> 2 17
I/Position: gravity -> 1 17
I/Position: position -> 0
I/Position: gravity -> 0 8388627
CodePudding user response:
I believe the RecyclerView tries to use old rows to save on memory usage. It's kinda like: when the view 0 goes out the screen, the new line 9 will "recycle" it to show itself (that why it's called RecyclerView).
If you want a different first line, try override the method int getItemViewType(int position)
and specify that the first item is a "different type" from the rest
(or you could just add an else on if(position == 0)
and force the gravity you want, but I think the other option is more elegant)
CodePudding user response:
ReyclerView
s have a handful of ViewHolder
s that they swap around to make it look like a large list, but really it's the same few boxes riding along a conveyor belt, being moved from the end back to the start.
onBindViewHolder
is where you set the contents of one of those boxes to display the item at that position in the list. The ViewHolder
that you're provided with still looks like it did when it was set up to display a previous item, so you need to make sure everything is set up correctly for the new one. Anything you don't change, will stick and look like the last item it was displaying.
So here's your problem:
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
viewHolder.textView.text = dataSet[position]
if(position == 0) {
viewHolder.textView.gravity = Gravity.START or Gravity.CENTER_VERTICAL
}
}
Part of the display state that changes between items is the gravity - and here you're setting it for item 0, but you're not setting it to normal for the other items. It's sticky, you only set it one way, and it can never revert. So the next item that needs to display in that recycled ViewHolder
object will have that same gravity setting, because that's what it's been set to! Which is item 9 going by your logs (you can see how many ViewHolder
s are getting created by when the reuse starts - looks like it happens to use 9 of them in this case)
So yeah, you need to set the gravity in all cases - set the whole display state for every item, to ensure it's consistent and that none of the old state can influence how it looks now:
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
viewHolder.textView.text = dataSet[position]
// explicitly set the gravity every time
if(position == 0) {
viewHolder.textView.gravity = Gravity.START or Gravity.CENTER_VERTICAL
} else {
viewHolder.textView.gravity = // whatever
}
}
But I hope that makes the broader point clearer - you always need to do this stuff with RecyclerView
s when you're binding items, because you're reusing old items that are filled in with old data and old state. So you should fully configure them each time, for anything that could potentially change. You don't want any old state hanging around!
(Luiz's answer is also a good option, having a completely separate item type for a header allows you to use a different ViewHolder
with its own layout etc, so there's no need to keep reconfiguring a single layout. But it might be too much work if you're making a small change - you have options!)