简体   繁体   中英

Recylerview add space below last item added in list ( ItemDecoration not updating)

I'm trying to have a space at the end of the last item in a RecyclerView.

For this I am using a ItemDecoration, but when adding a new item, both the previos item, and the new item will have the Bottom Offset. If I add a 3rd Item, the first item will no longer have offset, but the 2nd and newly added 3rd will have.

Below is my ItemDecoration class

class BottomOffsetDecoration : RecyclerView.ItemDecoration() {

override fun getItemOffsets(
    outRect: Rect,
    view: View,
    parent: RecyclerView,
    state: RecyclerView.State
) {
    super.getItemOffsets(outRect, view, parent, state)
    //dimension of offset
    val bottomOffset = view.context.resources.getDimension(R.dimen.player_list_offset).toInt()
    
    val dataSize = state.itemCount
    val position = parent.getChildAdapterPosition(view)
    
    //Logic of showing space or not
    if (dataSize > 0 && position == dataSize - 1) {
        outRect.set(0, 0, 0, bottomOffset)
    } else {
        outRect.setEmpty()
    }
}  
}

This gets added to my Recyclerview with Databinding like this:

@BindingAdapter(value = ["adapterListener", "itemList"])
  fun RecyclerView.bindList(adapterListener: PlayerListItemListener, itemList: List<PlayerListItem>) {
var adapter = this.adapter
//copy the list as DiffUtils will ignore it if it is the same list every call
val listCopy = ArrayList(itemList)

if (adapter == null) {
    adapter = PlayerListAdapter(adapterListener)
    this.apply {
        setAdapter(adapter)
        
        //DECORATION
        addItemDecoration(BottomOffsetDecoration())
        
        setHasFixedSize(true)
    }
}

(adapter as PlayerListAdapter).submitList(listCopy)
}

As for Recylerview Adapter I am using the ListAdapter with DiffUtils, not the RecyclerView.Adapter

Question is: how do I remove the offset from the last item once a new Item is added?

DISCLAIMER: I can not use the below for my case:

      android:paddingBottom="50dp"
      android:clipToPadding="false"

Thank you in advance!

So, for anyone else coming across this problem, here is how I solved it.

You need to call invalidateItemDecorations() after ListAdapter applied the changes to the list.

In my case I used submitList(list, commitCallback) , like below inside my BindingAdapter method:

 (adapter as PlayerListAdapter).submitList(listCopy) {
    post {
        //remove decoration from other elements so the bottom offset is added to only the last element inserted
        invalidateItemDecorations()
    }
}

I also updated my getItemOffset() , this was not part of the problem, but I like this code more:

 override fun getItemOffsets(
    outRect: Rect,
    view: View,
    parent: RecyclerView,
    state: RecyclerView.State
) {
    super.getItemOffsets(outRect, view, parent, state)
    val bottomOffset = view.context.resources.getDimension(R.dimen.player_list_offset).toInt()

    val adapter = parent.adapter
    if (adapter == null || adapter.itemCount == 0) {
        return
    }

    if (parent.getChildAdapterPosition(view) == adapter.itemCount - 1) {
        outRect.bottom = bottomOffset
    } else {
        outRect.bottom = 0
    }
}

Happy coding!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM