scrollBy doesn't work properly in nested recyclerview

前端 未结 1 1790
死守一世寂寞
死守一世寂寞 2021-02-05 16:34

I have a vertically scrolling RecyclerView with horizontally scrolling inner RecyclerViews just like this.

With this implementation, users can scro

1条回答
  •  长发绾君心
    2021-02-05 17:11

    I found a solution that is use scrollToPositionWithOffset method instead using scrollBy. Even if both of two scroll another position, they have really different work process in back side.

    For example: if you try to use scrollBy to scroll any pixel position and your recyclerView had not been set any adapter which means there is no any data to display and so it has no any items yet, then scrollBy doesn't work. RecyclerView uses its layoutManager's scrollBy method. So in my case, I am using LinearLayoutManager to the horizontal recyclerViews.

    Lets see what it's doing :

    int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
            if (getChildCount() == 0 || dy == 0) {
                return 0;
            }
            mLayoutState.mRecycle = true;
            ensureLayoutState();
            final int layoutDirection = dy > 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START;
            final int absDy = Math.abs(dy);
            updateLayoutState(layoutDirection, absDy, true, state);
            final int consumed = mLayoutState.mScrollingOffset
                    + fill(recycler, mLayoutState, state, false);
            if (consumed < 0) {
                if (DEBUG) {
                    Log.d(TAG, "Don't have any more elements to scroll");
                }
                return 0;
            }
            final int scrolled = absDy > consumed ? layoutDirection * consumed : dy;
            mOrientationHelper.offsetChildren(-scrolled);
            if (DEBUG) {
                Log.d(TAG, "scroll req: " + dy + " scrolled: " + scrolled);
            }
            mLayoutState.mLastScrollDelta = scrolled;
            return scrolled;
        }
    

    As you can see scrollBy ignores the scroll intentions if there is no any child at that time.

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

    On the other hand scrollToPosition can work perfectly even if there is no any set data yet.

    According to the Pro RecyclerView slide, the below sample works perfectly. However you can not do that with scrollBy.

    void onCreate(SavedInstanceState state) {
        ....
        mRecyclerView.scrollToPosition(selectedPosition);
        mRecyclerView.setAdapter(myAdapter);
    }
    

    As a result, I have changed little thing to use scrollToPositionWithOffset().

    Before this implementation I was calculating the exact scroll x position as a pixel.

    After that, when the scroll came idle state, calculating the first complete visible position to the first parameter of the scrollToPositionWithOffset().

    For second parameter which is the offset, I am getting the value using view.getLeft() function which helps to get left position of this view relative to its parent.

    And it works perfectly!!

    0 讨论(0)
提交回复
热议问题