1

I want to determine the most visible item in my RecyclerView and so I use the following method:

public int getMostVisibleIndex() {
        // try to figure which child is the most visible on screen

        LinearLayoutManager layoutManager = ((LinearLayoutManager) getLayoutManager());

        mFirstVisibleIndex = layoutManager.findFirstVisibleItemPosition();
        mLastVisibleIndex = layoutManager.findLastVisibleItemPosition();

        // How do I use convertPreLayoutPositionToPostLayout() ?

        VisibleIndex mostVisible = null;
        if (mFirstVisibleIndex != -1|| mLastVisibleIndex != -1) {


            // if it's not the same
            if (mFirstVisibleIndex != mLastVisibleIndex) {
                LinearLayoutManager linearLayoutManager = (LinearLayoutManager) this.getLayoutManager();

                // get the visible rect of the first item
                Rect firstPercentageRect = new Rect();
                linearLayoutManager.findViewByPosition(mFirstVisibleIndex).getGlobalVisibleRect(firstPercentageRect);

                // get the visible rect of the last item
                Rect lastPercentageRect = new Rect();
                linearLayoutManager.findViewByPosition(mLastVisibleIndex).getGlobalVisibleRect(lastPercentageRect);

                // since we're on a horizontal list
                if (firstPercentageRect.width() > lastPercentageRect.width()) {
                    return mFirstVisibleIndex;
                } else {
                    return mLastVisibleIndex;
                }

            } else {
                return mFirstVisibleIndex;
            }
        }
        return -1;
    }

It works great, but after I change the data set, and call any notify*Changed methods in my adapter, if I try to use the above function, the item positions that findFirstVisibleItemPosition and findLastVisibleItemPosition return are wrong.

I noticed that they both use getlayoutposition behind the scenes, and I also noticed that on the documentation it says:

If LayoutManager needs to call an external method that requires the adapter position of the item, it can use getAdapterPosition() or convertPreLayoutPositionToPostLayout(int).

It sounds as if convertPreLayoutPositionToPostLayout is EXACTLY what I'm looking for, but I have no idea how to access it from within a RecyclerView.

Any ideas?

Thank you.

SudoPlz
  • 20,996
  • 12
  • 82
  • 123

1 Answers1

2

In my case I can only have maximum 2 visible views at a time in recyclerview and I am using this method in onScrolled for always having the mostVisibleItemPosition for playing video content when user scrolls.

So getTop() returns top position of this view relative to its parent and when user starts scrolling firstView is getting out of the screen and the firstView.getTop() will return minus value while secondView.getTop() is positive and when secondView top reaches nearly the center of the screen getting absolute value of firstView.getTop() we will determine how many pixels firstView top is above from parent view top and getting secondView.getTop() we will determine how many pixels secondView top is above parent bottom and this is where mostVisibleItemPosition will changed.

  private void detectMostVisibleItem() {
        int firstItemPosition = layoutManager.findFirstVisibleItemPosition();
        int secondItemPosition = layoutManager.findLastVisibleItemPosition();
        if (firstItemPosition == secondItemPosition) {
            mostVisibleItemPosition = firstItemPosition;
        } else {
            View firstView = layoutManager.findViewByPosition(firstItemPosition);
            View secondView = layoutManager.findViewByPosition(secondItemPosition);
            if (Math.abs(firstView.getTop()) <= Math.abs(secondView.getTop())) {
                if (mostVisibleItemPosition != firstItemPosition) {
                    mostVisibleItemPosition = firstItemPosition;
                 ...
                }
            } else {
                if (mostVisibleItemPosition != secondItemPosition) {
                    mostVisibleItemPosition = secondItemPosition;
                 ...
                }
            }
        }
    }
Levon Petrosyan
  • 8,815
  • 8
  • 54
  • 65
  • Would you be kind enough to explain why this will yield the correct results even after `notify*Changed` methods get called? – SudoPlz Oct 04 '18 at 00:14