Created
September 22, 2015 08:49
-
-
Save SangsooNam/90c158d90b8f8f49610d to your computer and use it in GitHub Desktop.
ScrollToPosition bug fixed version of GridLayoutManager
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package android.support.v7.widget; | |
import android.content.Context; | |
import android.util.AttributeSet; | |
import android.view.View; | |
/** | |
* Bug fixed version of GridLayoutManager | |
* Created by SangsooNam on 20/09/15. | |
* <p/> | |
* --- Bug --- | |
* <br> | |
* https://code.google.com/p/android/issues/detail?id=182517 | |
* <br> | |
* After calling `scrollToPosition`, only first grid column is shown and others are shown in | |
* the other row. This is due to wrong `anchorInfo.mPosition`. There are two modes depending on the | |
* value `anchorInfo.mLayoutFromEnd`. One is to layout from start to end, and the other is to layout | |
* from end to start. When to layout from start to end, `ensureAnchorInFirstSpan` is reasonable. | |
* However, it doesn't make sense when to layout from end to start. At that time, we need to ensure | |
* that anchor is in the last span instead of the first. This class is fixing that issue. | |
*/ | |
public class GridLayoutQuirksFixedManager extends GridLayoutManager { | |
public GridLayoutQuirksFixedManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { | |
super(context, attrs, defStyleAttr, defStyleRes); | |
} | |
public GridLayoutQuirksFixedManager(Context context, int spanCount) { | |
super(context, spanCount); | |
} | |
public GridLayoutQuirksFixedManager(Context context, int spanCount, int orientation, boolean reverseLayout) { | |
super(context, spanCount, orientation, reverseLayout); | |
} | |
@Override | |
void onAnchorReady(RecyclerView.State state, AnchorInfo anchorInfo) { | |
updateMeasurements(); | |
if (state.getItemCount() > 0 && !state.isPreLayout()) { | |
if (anchorInfo.mLayoutFromEnd) { | |
ensureAnchorIsInLastSpan(anchorInfo); | |
} else { | |
ensureAnchorIsInFirstSpan(anchorInfo); | |
} | |
} | |
if (mSet == null || mSet.length != mSpanCount) { | |
mSet = new View[mSpanCount]; | |
} | |
} | |
private void ensureAnchorIsInLastSpan(AnchorInfo anchorInfo) { | |
int spanIndex = mSpanSizeLookup.getCachedSpanIndex(anchorInfo.mPosition, mSpanCount); | |
int spanSize = mSpanSizeLookup.getSpanSize(anchorInfo.mPosition); | |
while (spanIndex + spanSize < mSpanCount && anchorInfo.mPosition < getItemCount()) { | |
anchorInfo.mPosition++; | |
spanIndex = mSpanSizeLookup.getCachedSpanIndex(anchorInfo.mPosition, mSpanCount); | |
spanSize = mSpanSizeLookup.getSpanSize(anchorInfo.mPosition); | |
} | |
} | |
/** | |
* The same code from GridLayoutManager | |
*/ | |
private void ensureAnchorIsInFirstSpan(AnchorInfo anchorInfo) { | |
int span = mSpanSizeLookup.getCachedSpanIndex(anchorInfo.mPosition, mSpanCount); | |
while (span > 0 && anchorInfo.mPosition > 0) { | |
anchorInfo.mPosition--; | |
span = mSpanSizeLookup.getCachedSpanIndex(anchorInfo.mPosition, mSpanCount); | |
} | |
} | |
/** | |
* The same code from GridLayoutManager | |
*/ | |
private void updateMeasurements() { | |
int totalSpace; | |
if (getOrientation() == VERTICAL) { | |
totalSpace = getWidth() - getPaddingRight() - getPaddingLeft(); | |
} else { | |
totalSpace = getHeight() - getPaddingBottom() - getPaddingTop(); | |
} | |
calculateItemBorders(totalSpace); | |
} | |
/** | |
* The same code from GridLayoutManager | |
*/ | |
private void calculateItemBorders(int totalSpace) { | |
if (mCachedBorders == null || mCachedBorders.length != mSpanCount + 1 | |
|| mCachedBorders[mCachedBorders.length - 1] != totalSpace) { | |
mCachedBorders = new int[mSpanCount + 1]; | |
} | |
mCachedBorders[0] = 0; | |
int sizePerSpan = totalSpace / mSpanCount; | |
int sizePerSpanRemainder = totalSpace % mSpanCount; | |
int consumedPixels = 0; | |
int additionalSize = 0; | |
for (int i = 1; i <= mSpanCount; i++) { | |
int itemSize = sizePerSpan; | |
additionalSize += sizePerSpanRemainder; | |
if (additionalSize > 0 && (mSpanCount - additionalSize) < sizePerSpanRemainder) { | |
itemSize += 1; | |
additionalSize -= mSpanCount; | |
} | |
consumedPixels += itemSize; | |
mCachedBorders[i] = consumedPixels; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment