androidandroid-layoutandroid-recyclerviewstaggeredgridlayoutmanager

StaggeredGridLayoutManager reorders items without respecting to defined margins


I', using StaggeredGridLayoutManager for my RecyclerView in order to show items in 2 columns with equal widths but different heights. since I want equal gap between items the following ItemDecoration is being used:

public class ImageCardDecoration extends RecyclerView.ItemDecoration {
    private int margin;

    public ImageCardDecoration(Context context) {
        margin = 5;
    }

    @Override
    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);

        int position = parent.getChildAdapterPosition(view);
        int spanIndex =((StaggeredGridLayoutManager.LayoutParams)view.getLayoutParams()).getSpanIndex();
        if (spanIndex == 0) {
            outRect.left = 2 * margin;
            outRect.right = margin;
        } else {
            outRect.left = margin;
            outRect.right = 2 * margin;
        }
        outRect.top = 2 * margin;

        if (position == 0 || position == 1)
            outRect.top = 14 * margin;
    }
}

and it works fine. but after scrolling the recyclerview and when it gets Idle, the layout manager reorder some items to fill the gaps (this is good, I want this behavior), but if an item is moved from 2nd column to 1st column, it doesn't use the margins defined for 1st column in the above code and also if the item moves from 1st column to 2nd column, again it doesn't update its margins. how to solve this misbehavior?! before reorderingafter reordering


Solution

  • the following solution worked like a charm!

            recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull final RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
    
                if (newState == RecyclerView.SCROLL_STATE_IDLE)
                    recyclerView.invalidateItemDecorations();
            }
    }