Reputation: 1840
So, I'm facing a weird problem while implementing RecyclerView in my project. I have a custom decorator to implement a consistent top and bottom padding and a rather different value of padding in between elements. Whenever I tap on refresh, i.e. fetch data from back-end and populate RecyclerView again, the padding increases and it keeps on increasing on each refresh.
When I hit refresh (causing AsyncTask to execute again), the space between items increase. And it keeps on increase with each refresh.
I have a typical RecyclerView like this
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="false"
android:focusableInTouchMode="false">
</android.support.v7.widget.RecyclerView>
Populating content inside RecyclerView is CardView with the following layout:
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/cv"
android:layout_marginLeft="9dp"
android:layout_marginRight="9dp"
>
<RelativeLayout
android:id="@+id/itemLinearTop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="17dp"
android:paddingRight="10dp"
android:paddingLeft="10dp">
<TextView
android:id="@+id/tv1"
android:textColor="@color/logo_black"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/tv1"
android:textColor="@color/logo_black"
android:layout_alignParentRight="true"
android:textAppearance="?android:attr/textAppearanceMedium" />
<!-- More elements -->
</RelativeLayout>
</android.support.v7.widget.CardView>
I am initializing and populating RecyclerView like this:
// In PostExecute of AsyncTask
RecyclerView rv = (RecyclerView) rootView.findViewById(R.id.recyclerview);
RecycleViewAdapter adapter = new FuelPricesRecycleViewAdapter(data);
rv.setAdapter(adapter);
rv.addItemDecoration(new RecyclerViewItemDecoration(30, item_count - 1));
And this is what my RecyclerViewItemDecoration class looks like:
public class RecyclerViewItemDecoration extends RecyclerView.ItemDecoration {
private int space = 0;
private int item_count = 0;
private int ADDITIONAL_PADDING = 20;
public RecyclerViewItemDecoration(int space, int item_count) {
this.space = space;
this.item_count = item_count;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
if(parent.getChildPosition(view) != item_count)
outRect.bottom = space;
// Add top margin only for the first item to avoid double space between items
if(parent.getChildPosition(view) == 0)
outRect.top = space + ADDITIONAL_PADDING;
if(parent.getChildPosition(view) == item_count)
outRect.bottom = space + ADDITIONAL_PADDING;
}
}
Thank you for your help!
Upvotes: 28
Views: 18379
Reputation: 101
I had the same issue and I fixed that with the itemDecorationCount
if (recyclerView.itemDecorationCount == 0) {
val itemDecorator = DividerItemDecoration(activity, DividerItemDecoration.VERTICAL)
itemDecorator.setDrawable(ContextCompat.getDrawable(activity, R.drawable.recycler_divider))
recyclerView.addItemDecoration(itemDecorator)
}
Upvotes: 10
Reputation: 1377
This is happening because we are trying to add itemDecorator to the recycler view which already have itemDecorator added to it, check first if its already there then don't add again
if (0 == recyclerview.getItemDecorationCount()) {
recyclerview.addItemDecoration(new DividerItemDecoration(ContextCompat.getDrawable(getActivity(), R.drawable.divider)));
}
This 0 will be the number of itemDecorator we have in recycler view, most of the time it'll be 0.
Upvotes: 24
Reputation: 2208
You are adding Decoration
each time recyclerview is loaded.
Use one flag instead :
private boolean flagDecoration = false;
if(!flagDecoration)
{
rv.addItemDecoration(new RecyclerViewItemDecoration(30, item_count - 1));
flagDecoration = true;
}
Upvotes: 15
Reputation: 71
Apparently you are adding various decorations. I was having the same problem. What I did here and that worked out was:
1º - Declare the decoration before the onCreate () method:
public StickyHeaderDecoration mDecor;
public MyAdapterPinned MyAdapterPinned;
2º - Then I created a method that creates and populates my recycleview. In this method I check if I have already called mDecor. If so, I remove it. Otherwise, I create it. The code looks like this:
public void createRecyclerView(){
//hide layout com progress
hideLayoutProgressFull();
LinearLayoutManager mLayoutManager = new
LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
myAdapterPinned = new MyAdapterPinned(getContext(), mList);
recyclerView.setAdapter(myAdapterPinned);
if (mDecor != null)
recyclerView.removeItemDecoration(mDecor);
mDecor = new StickyHeaderDecoration(myAdapterPinned);
recyclerView.addItemDecoration(mDecor);
//hide progressDialog
hideProgress();
}
NOTE: I am using an adapter that sets the title to each change but you can not interfere with the result. You can use your ordinary adapter. It worked for me. I hope it works for you too;
Upvotes: 0
Reputation: 819
I face the same issue. Fix it with if check
if (recyclerView.getItemDecorationAt(0) == null) { // check decoration here
FlexboxItemDecoration agentDividerItemDecoration = new FlexboxItemDecoration(rv.getContext());
agentDividerItemDecoration.setDrawable(recyclerView.getContext().getResources().getDrawable(R.drawable.shape_divider_flex_normal));
recyclerView.addItemDecoration(agentDividerItemDecoration);
} else {
Log.i(TAG, "initTagsView: ItemDecoration not null");
}
Upvotes: 1
Reputation: 378
Faced the same issue and resolved it by placing
mLayoutManager = new LinearLayoutManager(current_activity);
recyclerView.setLayoutManager(mLayoutManager);
in onPreExecute()
method.
Just give it a try if it works
Upvotes: 1
Reputation: 11
I was facing the same issue, the best solution is to make your item decoration while your are initializing your layout manager in the view holder , this resolves the problem you are facing example
public class GridViewHolder extends ViewHolder {
RecyclerView grid_list;
public GridViewHolder(View v) {
super(v);
this.grid_list = (RecyclerView) v.findViewById(R.id.home_screen_item_grid_recycler_view);
if (grid_list.getLayoutManager() == null) {
RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(context, 4);
grid_list.setLayoutManager(mLayoutManager);
grid_list.addItemDecoration(new GridSpacingItemDecoration(4, 3, false));
}
}
}
Upvotes: 1
Reputation: 6690
You have to remove the item decoration before reseting new data.
rv.removeItemDecoration(yourDecorator)
Let me know if it works!
Upvotes: 17