Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - ItemDecoration sometimes gone or misplaced while adding item or scrolling

Tags:

android

I have just started using ItemDecoration. I am trying to achieve a divider in the middle of a two-column RecyclerView managed by StaggeredGridLayoutManager.

Here's my ItemDecoration code :

public class LobbyItemDecoration extends RecyclerView.ItemDecoration {

    private int margin;
    private Drawable drawable;

    public LobbyItemDecoration(int margin, Drawable drawable){
        this.margin = margin;
        this.drawable = drawable;
    }

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

        StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams)view .getLayoutParams();
        int spanIndex = lp.getSpanIndex();

        if(position >= 0){
            if (position < ((LobiAdapter)parent.getAdapter()).getmDataset().size()){
                if(spanIndex == 1){
                    outRect.left = margin;
                    ((LobiAdapter)parent.getAdapter()).getmDataset().get(position).left = false;
                } else {
                    outRect.right = margin;
                    ((LobiAdapter)parent.getAdapter()).getmDataset().get(position).left = true;
                }
                outRect.bottom = margin;
            }
        }
    }

    @Override
    public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
        if (drawable == null) { super.onDrawOver(c, parent, state);return; }

        if(parent.getItemAnimator() != null && parent.getItemAnimator().isRunning()) {
            return;
        }

        final int top = parent.getPaddingTop();
        final int bottom = parent.getHeight() - parent.getPaddingBottom();
        final int childCount = parent.getChildCount();

        for (int i=1; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            StaggeredGridLayoutManager.LayoutParams lp = (StaggeredGridLayoutManager.LayoutParams)child .getLayoutParams();
            int spanIndex = lp.getSpanIndex();
            int size = drawable.getIntrinsicWidth();
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            final int ty = (int)(child.getTranslationY() + 0.5f);
            final int tx = (int)(child.getTranslationX() + 0.5f);
            final int leftIndex1 = child.getLeft() - (margin * 4 / 3) - tx;
            final int rightIndex1 = child.getLeft() - (margin * 2 / 3) - tx;
            final int leftIndex0 = child.getRight() + (margin * 2 / 3) + tx;
            final int rightIndex0 = child.getRight() + (margin * 4 / 3) + tx;
            if(spanIndex == 1){
//                drawable.setBounds(100, top, 5, bottom);
                drawable.setBounds(leftIndex1, top, rightIndex1, bottom);
                drawable.draw(c);
            } else {
                drawable.setBounds(leftIndex0, top, rightIndex0, bottom);
                drawable.draw(c);
//                drawable.setBounds(5, top, 100, bottom);
            }
        }
    }
}

Problem is as title said, whenever I load new item or scroll, the decoration is sometimes gone or misplaced. By gone I mean, literally gone, it's not there anymore until I scroll down or up to recycle the View.

And by misplaced I mean, when I scroll down, and the loading ViewHolder is in the left column, the divider "sticks" to the left column. If the loading ViewHolder is in the right column, it is normal.

Just in case : I use a ViewHolder to be a progress indicator by adding one null item and check it in getItemViewType() then remove it later after finishing the load from server.

This is how I add :

for (PostModel postModel :
        dataSet) {
    this.mDataset.add(postModel);
    notifyItemInserted(mDataset.size() - 1);
}
like image 896
Kevin Murvie Avatar asked Sep 19 '16 03:09

Kevin Murvie


1 Answers

StaggeredGridLayoutManager is buggy. For me this helped:

  diffResult.dispatchUpdatesTo(this);
  recyclerView.postDelayed(() -> {
        layoutManager.invalidateSpanAssignments(); // to fix first item in second column issue
        recyclerView.invalidateItemDecorations(); // to fix wrong spacing
  }, 50);
like image 109
Andoctorey Avatar answered Nov 25 '22 11:11

Andoctorey