David Berry
David Berry

Reputation: 41236

RecyclerView Decoration doesn't scroll correctly

I have a RecyclerView which uses a simple line separator Decoration.

The decoration is fine except when a NEW item is added to the bottom of the recycler and scrolled into view, the decoration is initially drawn in it's final location and then the view underneath scrolls into place, but the decoration doesn't scroll.

The desired behavior would be for the decoration to be drawn in it's starting location and then scroll into position along with the new item.

Here's the relevant portions of the Decoration:

class NormalDecoration extends RecyclerView.ItemDecoration {
    private int spacing;
    private Drawable drawable;

    NormalDecoration(Context context) {
        spacing = context.getResources().getDimensionPixelOffset(R.dimen.chat_separator_height);
        drawable = ContextCompat.getDrawable(context, R.drawable.chat_divider);
    }

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

        if (applySpacing(view, parent)) {
            outRect.top += spacing;
        }
    }

    boolean applySpacing(View view, RecyclerView parent) {
        int position = parent.getChildAdapterPosition(view);

        return position != -1 && position < mItems.size();
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int dividerLeft = parent.getPaddingLeft();
        int dividerRight = parent.getWidth() - parent.getPaddingRight();

        for(int index = parent.getChildCount() - 1 ; index >= 0 ; --index) {
            View view = parent.getChildAt(index);

            if(applySpacing(view, parent)) {
                RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();

                int dividerTop = view.getBottom() + params.bottomMargin;
                int dividerBottom = dividerTop + spacing;

                drawable.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom);
                drawable.draw(c);
            }
        }
    }
}

My Adapter contains the following helper:

class Adapter {
    public void add(final int index, final IChatMessageItem item) {
        mItems.add(index, item);
        notifyItemInserted(index);
    }
}

And here's how I add the item to the recycler that results in unacceptable scrolling behavior:

...
adapter.add(index, item);
layout.scrollToPosition(index);
...

Upvotes: 0

Views: 993

Answers (1)

David Medenjak
David Medenjak

Reputation: 34542

You need to use view.getTranslationX(), getTranslationY(), and getAlpha() respectively to animate the decoration along with the view moving.

If you just draw a divider, you might want to use the official support decoration which also does the above mentioned.

I also wrote an article about this in detail here.

Upvotes: 2

Related Questions