2015-04-22 142 views
0

我和這裏幾乎一樣(https://github.com/kmshack/Android-ParallaxHeaderViewPager),但在標籤中使用了RecyclerView。StaggeredGridLayoutManager返回錯誤verticalScrollOffset

RecyclerView在一個選項卡中包含高度較大的項目,並且第一個項目在標題下並不總是完全可見。我調用RecyclerView的computeVerticalScrollOffset()(它調用StaggeredGridLayoutManager的方法),它返回完全錯誤的值。如果我更改標題高度以使第一個項目完全可見,我會得到正確的值。

是否有任何已知的解決方案/修復?

P.S.我也用LinearLayoutManager,一定可以得到即使第一個項目是不是在頭完全可見,正確的價值觀

回答

0

讓我們跟隨的RecyclerView源代碼:

@Override 
public int computeVerticalScrollOffset() { 
    return mLayout.canScrollVertically() ? mLayout.computeVerticalScrollOffset(mState) : 0; 
} 

mLayout是LayoutManager一個實例。在我們的案例中,它應該屬於StaggeredGridLayoutManager。讓我們來看看有:

@Override 
public int computeVerticalScrollOffset(RecyclerView.State state) { 
    return computeScrollOffset(state); 
} 

然後在這裏:

private int computeScrollOffset(RecyclerView.State state) { 
    if (getChildCount() == 0) { 
     return 0; 
    } 
    ensureOrientationHelper(); 
    return ScrollbarHelper.computeScrollOffset(state, mPrimaryOrientation, 
      findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled, true) 
      , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled, true), 
      this, mSmoothScrollbarEnabled, mShouldReverseLayout); 
} 

最後,我們去ScrollbarHelper.computeScrollOffset:

/** 
* @param startChild View closest to start of the list. (top or left) 
* @param endChild View closest to end of the list (bottom or right) 
*/ 
static int computeScrollOffset(RecyclerView.State state, OrientationHelper orientation, 
     View startChild, View endChild, RecyclerView.LayoutManager lm, 
     boolean smoothScrollbarEnabled, boolean reverseLayout) { 
    if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null || 
      endChild == null) { 
     return 0; 
    } 
    final int minPosition = Math.min(lm.getPosition(startChild), 
      lm.getPosition(endChild)); 
    final int maxPosition = Math.max(lm.getPosition(startChild), 
      lm.getPosition(endChild)); 
    final int itemsBefore = reverseLayout 
      ? Math.max(0, state.getItemCount() - maxPosition - 1) 
      : Math.max(0, minPosition); 
    if (!smoothScrollbarEnabled) { 
     return itemsBefore; 
    } 
    final int laidOutArea = Math.abs(orientation.getDecoratedEnd(endChild) - 
      orientation.getDecoratedStart(startChild)); 
    final int itemRange = Math.abs(lm.getPosition(startChild) - 
      lm.getPosition(endChild)) + 1; 
    final float avgSizePerRow = (float) laidOutArea/itemRange; 

    return Math.round(itemsBefore * avgSizePerRow + (orientation.getStartAfterPadding() 
      - orientation.getDecoratedStart(startChild))); 
} 

我們應該專注於最後一條語句。此方法返回由項目* avgHeight計算的偏移量,當我們的項目具有各種高度時,這是不準確的。

因此,當我們使用的GridLayoutManager,由於確認了每一行的高度,所以computeVerticalScrollOffset()將返回正確的距離。但是,不幸的是,當我們使用StaggeredGridLayoutManager時,我們無法獲得精確的滾動偏移量。

P.S我知道它不正確的原因,但我不知道如何得到正確的滾動距離。如果有人知道,請訪問:How to get correct scroll distance of RecyclerView when using a StaggeredGridLayoutManager?併發布您的答案。

1

我相信錯誤是在computeScrollOffset()函數參數中使用findFirstVisiblePosition()和findLastVisiblePosition()。即使我使用幾乎相等的行高,computeVerticalScrollOffset()也會返回真正奇怪的數字。 如果我們用recyclerView.getChildAt(0)和recyclerView.getChildAt(recyclerView.getChildCount() - 1)替換它們實際工作。

所以我們可以寫我們自己的函數:

View firstItemView = recyclerView.getChildAt(0); 
View lastItemView = recyclerView.getChildAt(recyclerView.getChildCount() - 1); 

int firstItem = recyclerView.getChildLayoutPosition(firstItemView); 
int lastItem = recyclerView.getChildLayoutPosition(lastItemView); 
int itemsBefore = firstItem; 

int laidOutArea = recyclerView.getLayoutManager().getDecoratedBottom(lastItemView) - recyclerView.getLayoutManager().getDecoratedTop(firstItemView); 
int itemRange = lastItem - firstItem + 1; 
float avgSizePerRow = (float) laidOutArea/itemRange; 

int offset = (int) (itemsBefore * avgSizePerRow + recyclerView.getLayoutManager().getPaddingTop() - recyclerView.getLayoutManager().getDecoratedTop(firstItemView)); 
+0

真棒謝謝 –