8

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?

Vektor88
  • 4,429
  • 9
  • 52
  • 102
  • That´s because of the length of listView. The first and last items are not reachable. I had a similar problem and just added default invisible items to compensate the not reachable area. However, for this, you need to make some calculations for different screen sizes. But this is just a kind of hacky-wacky solution, maybe (I hope so) there is a better solution.. – Opiatefuchs Jun 26 '17 at 18:35
  • @Opiatefuchs theorically the artificial offset added by my `ItemDecoration` should prevent me from creating such dummy items. – Vektor88 Jun 26 '17 at 18:51
  • yes....theoretically....I hadn´t any success with the offset. But this wasn´t made for my needs. My goal was to have a horizontal recyclerView which let the items slide from left to right (and vice versa) to the screen end. The offset cuts the edges and the items doesn´t scroll until the end of the screen. Because of that problem, I decided to add some invisible views until I find another solution. – Opiatefuchs Jun 26 '17 at 19:19

1 Answers1

8

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.

Nexen
  • 1,407
  • 3
  • 13
  • 41