Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to consistently add alternating backgrounds to item views in RecyclerView

Up until now I used the Adapter's onBindViewHolder to set an alternating background based on the item's Adapter-Position.

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    holder.itemView.setBackgroundResource(position % 2 == 0 ?
            R.color.list_item_background_alternating : R.color.list_item_background);
    ...
}

However, this is getting more an more complicated when doing more than just showing a list. For example: When I remove an item and call notifyItemRemoved(index); the RecyclerView does a nice animation and the item view is gone. However, the view which replaces the removed one doesn't get bound again (for obvious & good reasons) and therefore keeps it's old background. This leads to inconsistencies with the layout and looks ugly. When I call notifyDataSetChanged(); the backgrounds are all correct, but I lose the animation.

I have a similar problem when I'm using SortedList (with a SortedListAdapterCallback). Since the sorting seems to take place after the views are bound the backgrounds are in shambles.

What would be a proper/consistent way to implement such behaviour?

like image 819
robocab Avatar asked Aug 14 '15 10:08

robocab


2 Answers

Alright, while I was writing up my question I wanted to try one thing out which I thought wouldn't work - however, it did.

I created an ItemDecoration and used it's getItemOffset(); to set the view's background:

public class BackgroundItemDecoration extends RecyclerView.ItemDecoration {

    private final int mOddBackground;
    private final int mEvenBackground;

    public BackgroundItemDecoration(@DrawableRes int oddBackground, @DrawableRes int evenBackground) {
        mOddBackground = oddBackground;
        mEvenBackground = evenBackground;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        int position = parent.getChildAdapterPosition(view);
        view.setBackgroundResource(position % 2 == 0 ? mEvenBackground : mOddBackground);
    }
}

I feel a bit guilty though, that I'm piggy-bagging on getItemOffsets().

Does anyone have a cleaner/better solution?

like image 54
robocab Avatar answered Nov 05 '22 07:11

robocab


This is my solution The itemView refers to the View from the Layout inflater in the onCreateViewHolder.

public void onBindViewHolder(MyViewHolder holder, int position){
    //alternate row color
            if(position % 2==0)
                holder.itemView.setBackgroundColor(Color.YELLOW);
            else
                holder.itemView.setBackgroundColor(Color.LTGRAY);
)

That is all you need. Hope this helps.

like image 2
user5727134 Avatar answered Nov 05 '22 08:11

user5727134