Skip to content

Instantly share code, notes, and snippets.

@wongcain
Created November 14, 2015 00:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wongcain/0b607c251d255f7d5ec3 to your computer and use it in GitHub Desktop.
Save wongcain/0b607c251d255f7d5ec3 to your computer and use it in GitHub Desktop.
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.
* Modified by Cain Wong on 13/11/15: Updated for Recyclerview-v7:22.2.1
* <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.Recycler recycler, RecyclerView.State state,
AnchorInfo anchorInfo) {
super.onAnchorReady(recycler, state, anchorInfo);
updateMeasurements();
if (state.getItemCount() > 0 && !state.isPreLayout()) {
if (anchorInfo.mLayoutFromEnd) {
ensureAnchorIsInLastSpan(recycler, state, anchorInfo);
} else {
ensureAnchorIsInFirstSpan(recycler, state, anchorInfo);
}
}
if (mSet == null || mSet.length != mSpanCount) {
mSet = new View[mSpanCount];
}
}
private void ensureAnchorIsInLastSpan(RecyclerView.Recycler recycler, RecyclerView.State state,
AnchorInfo anchorInfo) {
int spanIndex = getSpanIndex(recycler, state, anchorInfo.mPosition);
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(RecyclerView.Recycler recycler, RecyclerView.State state,
AnchorInfo anchorInfo) {
int span = getSpanIndex(recycler, state, anchorInfo.mPosition);
while (span > 0 && anchorInfo.mPosition > 0) {
anchorInfo.mPosition--;
span = getSpanIndex(recycler, state, anchorInfo.mPosition);
}
}
/**
* The same code from GridLayoutManager except commented out logging
*/
private int getSpanIndex(RecyclerView.Recycler recycler, RecyclerView.State state, int pos) {
if (!state.isPreLayout()) {
return mSpanSizeLookup.getCachedSpanIndex(pos, mSpanCount);
}
final int cached = mPreLayoutSpanIndexCache.get(pos, -1);
if (cached != -1) {
return cached;
}
final int adapterPosition = recycler.convertPreLayoutPositionToPostLayout(pos);
if (adapterPosition == -1) {
// if (DEBUG) {
// throw new RuntimeException("Cannot find span index for pre layout position. It is"
// + " not cached, not in the adapter. Pos:" + pos);
// }
// Log.w(TAG, "Cannot find span size for pre layout position. It is"
// + " not cached, not in the adapter. Pos:" + pos);
return 0;
}
return mSpanSizeLookup.getCachedSpanIndex(adapterPosition, 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