RecyclerView LinearLayoutManager computeVerticalScrollOffset() not returning correct value

recyclerview computeverticalscrolloffset
scrolltopositionwithoffset
recyclerview layoutmanager
android-recyclerview get current item position
recyclerview get scroll position
recyclerview getscrolly returns 0
recyclerview scrollto not working
recyclerview scroll listener

I am working with a RecyclerView and a corresponding LinearLayoutManager. I was adding some custom scrolling features to part of my app where I would translate a custom header object along with the scroll of the RecyclerView modeled after this project: https://github.com/boxme/ParallaxHeaderViewPager (which uses ListView instead of RecyclerView).

I ran into a weird issue though. It would scroll just fine for a while but then it would jump a few hundred pixels. I added log statements to see the offset computed by LinearLayoutManager.computeVerticalScrollOffset() as I scrolled as sure enough, the offset was randomly jumping from like 320 to 1200 then it would continue computing the offset appropriately from that point.

See my answer below on how I solved this!

The issue ended up being the fact that I had a very large invisible item in my list followed by a bunch of smaller items. It turns out that LinearLayoutManager.computeVerticalScrollOffset() takes average row height into account when calculating. This caused an issue for me since that large item at the top was throwing off the average height of the rows. I ended up solving this by adding a few smaller invisible items on top instead of one large one to keep the average row height accurate.

I hope this helps anyone who faces a similar issue!

Improving accuracy of computeVerticalScrollOffset() For , computeVerticalScrollOffset() takes average row height into account when extent and range for a cheaper and more proper solution. the code for the overriden LinearLayoutManager, sorry its kotlin though :( Int { if (childCount == 0) { return 0 } val firstChildPosition = findFirstVisibleItemPosition() val� Recently, I was stuck trying to figure out a way to get the current vertical scroll offset value on my recyclerview. So the first solution that popped into my head was to use the…

Thanks to this thread finally found a way to resolve this accurately, posting below the code for the overriden LinearLayoutManager, sorry its kotlin though :(, also you can read about this in more detail here

class LinearLayoutManagerWithAccurateOffset(context: Context?) : LinearLayoutManager(context) {

    // map of child adapter position to its height.
    private val childSizesMap = mutableMapOf<Int, Int>()

    override fun onLayoutCompleted(state: RecyclerView.State?) {
        super.onLayoutCompleted(state)
        for (i in 0 until childCount) {
            val child = getChildAt(i)
            childSizesMap[getPosition(child)] = child.height
        }
    }

    override fun computeVerticalScrollOffset(state: RecyclerView.State?): Int {
        if (childCount == 0) {
            return 0
        }
        val firstChildPosition = findFirstVisibleItemPosition()
        val firstChild = findViewByPosition(firstChildPosition)
        var scrolledY: Int = -firstChild.y.toInt()
        for (i in 0 until firstChildPosition) {
            scrolledY += childSizesMap[i] ?: 0
        }
        return scrolledY
    }

}

LinearLayoutManager, RecyclerView LinearLayoutManager computeVerticalScrollOffset() not returning correct computeVerticalScrollOffset() not returning correct value - android� open class LinearLayoutManager : RecyclerView computeVerticalScrollOffset prefetched when this LayoutManager's RecyclerView is nested inside

For anyone that want it, here's the java version :

public class LinearLayoutManagerAccurateOffset extends LinearLayoutManager {

    private HashMap<Integer, Integer> mChildSizesMap;

    public LinearLayoutManagerAccurateOffset(Context context, int layoutType, boolean reverseLayout) {
        super(context, layoutType, reverseLayout);
        mChildSizesMap = new HashMap<>();
    }

    @Override
    public void onLayoutCompleted(RecyclerView.State state) {
        super.onLayoutCompleted(state);
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            mChildSizesMap.put(getPosition(child), child.getHeight());
        }

    }

    @Override
    public int computeVerticalScrollOffset(RecyclerView.State state) {

        if (getChildCount() == 0) {
            return 0;
        }

        View firstChild = getChildAt(0);
        int firstChildPosition = getPosition(firstChild);
        int scrolledY = -(int) firstChild.getY();
        for (int i = 0; i < firstChildPosition; i++) {
            scrolledY += mChildSizesMap.get(i);
        }
        return scrolledY;
    }
}

RecyclerView.LayoutManager, Does your `RecyclerView` give bad vertical offsets, and ruin your parallax scrolling Improving accuracy of computeVerticalScrollOffset() For LinearLayoutManager computeVerticalScrollOffset() not returning correct value � void: addDisappearingView(View child, int index) . To be called only during onLayoutChildren(Recycler, State) to add a view to the layout that is known to be going away, either because it has been removed or because it is actually not in the visible portion of the container but is being laid out in order to inform RecyclerView in how to animate the item out of view.

Class androidx.recyclerview.widget.LinearLayoutManager, Returns the adapter position of the first fully visible view. Read RecyclerView. computeVerticalScrollOffset() for details. last layout pass. Note that, this value is not affected by layout orientation or item order traversal. If one of the layout specs is not EXACT , the RecyclerView will start the layout process. <androidx.recyclerview.widget.RecyclerView app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" android:orientation="vertical" > You can also add them using the tools namespace (i.e. tools:orientation and tools:layoutManager) and then it only impacts the IDE preview and you can continue setting those values in code.

LinearLayoutManager - Android, LinearLayoutManager, StaggeredGridLayoutManager Calculate a MeasureSpec value for measuring a child view in one dimension. Return the right padding of the parent RecyclerView Returns whether layout is hierarchical or not to be used for accessibility computeVerticalScrollOffset() for details. Tag: android,onclick,position,recyclerview. I have a recylcerview in a navigation drawer and I wish to find what position was clicked by the user in the recyclerview in a different activity. The way I have written the code currently always return 0 as the position. Can anyone help me out. Thanks in advance! Recyclerview in Navigation drawer code:

v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager , Returns the amount of extra space that should be laid out by LayoutManager. If one of the layout specs is not EXACT, the RecyclerView will start the layout process. For instance, GridLayoutManager overrides this value to handle the case where if it is vertical and has 3 computeVerticalScrollOffset() for details. I am trying to get the position of an item in my RecyclerView, but none of the methods I have tried have worked. I called getAdapterPosition() in my PersonViewHolder constructor and assigned its value to the integer position, which is used in the UnitOneFragment class to do something accordingly (see onClick() method).

Comments
  • Instead of doing that, you could override computeVerticalScrollOffset, extent and range for a cheaper and more proper solution.
  • That's a great idea! I was a little wary of overriding RecyclerView and LayoutManager methods since the classes are still relatively new and might change significantly in the future. I agree my solution was on the hackier side but at least it should still work if the class changes in the future :)
  • Those methods are mirrors from View so very very unlikely to change. Also, when we change a public method, we try to make it backward compatible if possible
  • @yigit any examples please?
  • could you elaborate a bit on the takes average row height into account ? how does actually cause the values calculated to be incorrect?
  • @urSus tagging you to the answer just in case if you're still interested after 2 years lol