Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LinearSnapHelper doesn't snap on edge items of RecyclerView

This is a follow-up to my previous question.

In my app I'm trying to have an horizontal RecyclerView that automatically snaps to the center item. To do so, I've attached a LinearSnapHelper to it. I've also created an item decoration that adds some left/right padding to the first/last element:

public class OffsetItemDecoration extends RecyclerView.ItemDecoration {

    private Context ctx;

    public OffsetItemDecoration(Context ctx){
        this.ctx = ctx;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        int nCols = ActivityUtils.getNumCols(ctx);
        int colWidth = (int)(getScreenWidth()/(float)(nCols));

        if(parent.getChildAdapterPosition(view) == 0){
            int offset = Math.round(getScreenWidth() / 2f - colWidth / 2f);
            setupOutRect(outRect, offset, true);
        }

        else if (parent.getChildAdapterPosition(view) == state.getItemCount()-1){
            int offset = Math.round(getScreenWidth() / 2f - colWidth / 2f);
            setupOutRect(outRect, offset, false);
        }
    }

    private void setupOutRect(Rect rect, int offset, boolean start){
        if(start) rect.left = offset;
        else rect.right = offset;
    }

    private  int getScreenWidth(){
        WindowManager wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        return size.x;
    }
}

The problem is that when the RecyclerView is populated the first time, the first item is centered in the screen and also selected, but when I try to horizontally scroll and I go back to the first item, the leftmost item I can select is the 2nd one (position 1). The same happens for the last item, the rightmost item that can be snapped to is the penultimate one. (state.getItemCount() - 2).

Do I need to implement a new SnapHelper or am I doing something wrong?

like image 214
Vektor88 Avatar asked Jun 26 '17 18:06

Vektor88


Video Answer


1 Answers

RecyclerView has own rules about ItemDecoration. He thinks about them as a part of the item itself. You can think, what your decoration (even if it's just a padding) is part of your my_item.xml itself.

LinearSnapHelper uses methods like LayoutManager.getDecoratedMeasuredWidth() to determine center of the view. And that's from where the problem occurs. It sees your first item much larger than you think, so it's center for the first view is acutally in (padding + view.getWidth()) / 2. It is much farther than center for the second view, which is normal view.getX() + view.getWidth() / 2.

like image 109
Nexen Avatar answered Oct 09 '22 08:10

Nexen