Skip to content

Commit

Permalink
Cache section data. Closes #42.
Browse files Browse the repository at this point in the history
Conflicts:
	library/src/main/java/com/tonicartos/superslim/LayoutManager.java

The section data cache is cleared each time a new layout pass is done.
When new section data is created it is immediately cached. This allows
the slm layout parameter to only be required (and sourced) from the
first section item.
  • Loading branch information
TonicArtos committed Mar 2, 2015
2 parents 81f966e + 6fd3382 commit b9d57de
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,15 @@ public void onBindViewHolder(CountryViewHolder holder, int position) {
} else {
lp.width = ViewGroup.LayoutParams.WRAP_CONTENT;
}
}

if (position == item.sectionFirstPosition) {
lp.setSlm(item.sectionManager == LINEAR ? LinearSLM.ID : GridSLM.ID);
lp.headerEndMarginIsAuto = !mMarginsFixed;
lp.headerStartMarginIsAuto = !mMarginsFixed;
lp.setColumnWidth(mContext.getResources().getDimensionPixelSize(R.dimen.grid_column_width));
}
lp.setSlm(item.sectionManager == LINEAR ? LinearSLM.ID : GridSLM.ID);
lp.setColumnWidth(mContext.getResources().getDimensionPixelSize(R.dimen.grid_column_width));

lp.setFirstPosition(item.sectionFirstPosition);
itemView.setLayoutParams(lp);
}
Expand Down
118 changes: 73 additions & 45 deletions library/src/main/java/com/tonicartos/superslim/LayoutManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public class LayoutManager extends RecyclerView.LayoutManager {

private boolean mSmoothScrollEnabled = true;

private SparseArray<SectionData> mSectionDataCache = new SparseArray<>();

public LayoutManager(Context context) {
mLinearSlm = new LinearSLM(this);
mGridSlm = new GridSLM(this, context);
Expand Down Expand Up @@ -81,10 +83,11 @@ public View findFirstCompletelyVisibleItem() {
View firstVisibleView = null;
SectionData sd = null;
for (int i = 0; i < getChildCount() - 1; i++) {
sd = new SectionData(this, getChildAt(0));
final SectionLayoutManager slm = getSlm(sd);
LayoutParams params = (LayoutParams) getChildAt(0).getLayoutParams();
final SectionLayoutManager slm = getSlm(params);

firstVisibleView = slm.findFirstCompletelyVisibleView(sd.firstPosition, false);
firstVisibleView =
slm.findFirstCompletelyVisibleView(params.getTestedFirstPosition(), false);
if (firstVisibleView != null) {
break;
}
Expand Down Expand Up @@ -144,14 +147,16 @@ public int findFirstCompletelyVisibleItemPosition() {
* @return Position of first visible item.
*/
public View findFirstVisibleItem() {
SectionData sd = new SectionData(this, getChildAt(0));
final SectionLayoutManager slm = getSlm(sd);
View firstVisibleView = slm.findFirstVisibleView(sd.firstPosition, false);
LayoutParams params = (LayoutParams) getChildAt(0).getLayoutParams();
final SectionLayoutManager slm = getSlm(params);
View firstVisibleView = slm.findFirstVisibleView(params.getTestedFirstPosition(), false);
int position = getPosition(firstVisibleView);
if (position > sd.firstPosition + 1 || position == sd.firstPosition) {
if (position > params.getTestedFirstPosition() + 1 ||
position == params.getTestedFirstPosition()) {
return firstVisibleView;
}
View first = findAttachedHeaderOrFirstViewForSection(sd.firstPosition, 0, Direction.START);
View first = findAttachedHeaderOrFirstViewForSection(
params.getTestedFirstPosition(), 0, Direction.START);
if (first == null) {
return firstVisibleView;
}
Expand Down Expand Up @@ -184,10 +189,10 @@ public int findFirstVisibleItemPosition() {
* @return Position of last completely visible item.
*/
public View findLastCompletelyVisibleItem() {
SectionData sd = new SectionData(this, getChildAt(getChildCount() - 1));
final SectionLayoutManager slm = getSlm(sd);
LayoutParams params = (LayoutParams) getChildAt(getChildCount() - 1).getLayoutParams();
final SectionLayoutManager slm = getSlm(params);

return slm.findLastCompletelyVisibleView(sd.firstPosition);
return slm.findLastCompletelyVisibleView(params.getTestedFirstPosition());
}

/**
Expand All @@ -196,10 +201,10 @@ public View findLastCompletelyVisibleItem() {
* @return Position of last completely visible item.
*/
public int findLastCompletelyVisibleItemPosition() {
SectionData sd = new SectionData(this, getChildAt(getChildCount() - 1));
final SectionLayoutManager slm = getSlm(sd);
LayoutParams params = (LayoutParams) getChildAt(getChildCount() - 1).getLayoutParams();
final SectionLayoutManager slm = getSlm(params);

return slm.findLastCompletelyVisibleItemPosition(sd.firstPosition);
return slm.findLastCompletelyVisibleItemPosition(params.getTestedFirstPosition());
}

/**
Expand All @@ -208,10 +213,10 @@ public int findLastCompletelyVisibleItemPosition() {
* @return Position of last visible item.
*/
public View findLastVisibleItem() {
SectionData sd = new SectionData(this, getChildAt(getChildCount() - 1));
final SectionLayoutManager slm = getSlm(sd);
LayoutParams params = (LayoutParams) getChildAt(getChildCount() - 1).getLayoutParams();
final SectionLayoutManager slm = getSlm(params);

return slm.findLastVisibleView(sd.firstPosition);
return slm.findLastVisibleView(params.getTestedFirstPosition());
}

/**
Expand All @@ -220,10 +225,10 @@ public View findLastVisibleItem() {
* @return Position of last visible item.
*/
public int findLastVisibleItemPosition() {
SectionData sd = new SectionData(this, getChildAt(getChildCount() - 1));
final SectionLayoutManager slm = getSlm(sd);
LayoutParams params = (LayoutParams) getChildAt(getChildCount() - 1).getLayoutParams();
final SectionLayoutManager slm = getSlm(params);

return slm.findLastVisibleItemPosition(sd.firstPosition);
return slm.findLastVisibleItemPosition(params.getTestedFirstPosition());
}

public boolean isSmoothScrollEnabled() {
Expand Down Expand Up @@ -257,13 +262,27 @@ public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State
}

detachAndScrapAttachedViews(recycler);
clearSectionDataCache();

LayoutState layoutState = new LayoutState(this, recycler, state);
int bottomLine = layoutChildren(requestedPosition, borderLine, layoutState);

fixOverscroll(bottomLine, layoutState);
}

private void clearSectionDataCache() {
mSectionDataCache.clear();
}

private SectionData getSectionData(int position, View view) {
SectionData sd = mSectionDataCache.get(position);
if (sd == null) {
sd = new SectionData(this, view);
mSectionDataCache.put(position, sd);
}
return sd;
}

@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
Expand Down Expand Up @@ -655,22 +674,24 @@ private int fillNextSectionToEnd(int leadingEdge, int markerLine, LayoutState st
return markerLine;
}

View last = getAnchorAtEnd();
final View last = getAnchorAtEnd();
int anchorPosition = getPosition(last) + 1;

if (anchorPosition >= state.recyclerState.getItemCount()) {
return markerLine;
}

LayoutState.View header = state.getView(anchorPosition);
SectionData sd = new SectionData(this, header.view);
if (sd.hasHeader) {
final LayoutState.View header = state.getView(anchorPosition);
final LayoutParams headerParams = header.getLayoutParams();
final SectionData sd;
if (headerParams.isHeader) {
measureHeader(header.view);
sd = new SectionData(this, header.view);
sd = getSectionData(anchorPosition, header.view);
markerLine = layoutHeaderTowardsEnd(header.view, markerLine, sd, state);
anchorPosition += 1;
} else {
state.cacheView(anchorPosition, header.view);
sd = getSectionData(anchorPosition, header.view);
}

if (anchorPosition < state.recyclerState.getItemCount()) {
Expand Down Expand Up @@ -725,11 +746,11 @@ private int fillNextSectionToStart(int leadingEdge, int markerLine, LayoutState

// Setup section data.
View header = getHeaderOrFirstViewForSection(sfp, Direction.START, state);
SectionData sd = new SectionData(this, header);
if (sd.hasHeader) {
LayoutParams headerParams = (LayoutParams) header.getLayoutParams();
if (headerParams.isHeader) {
measureHeader(header);
sd = new SectionData(this, header);
}
SectionData sd = getSectionData(sfp, header);

// Fill out section.
SectionLayoutManager slm = getSlm(sd);
Expand Down Expand Up @@ -772,7 +793,7 @@ private int fillToEnd(int leadingEdge, LayoutState state) {
LayoutParams anchorParams = (LayoutParams) anchor.getLayoutParams();
final int sfp = anchorParams.getTestedFirstPosition();
final View first = getHeaderOrFirstViewForSection(sfp, Direction.END, state);
final SectionData sd = new SectionData(this, first);
final SectionData sd = getSectionData(sfp, first);

final SectionLayoutManager slm = getSlm(sd);
int markerLine = slm.finishFillToEnd(leadingEdge, anchor, sd, state);
Expand Down Expand Up @@ -800,7 +821,7 @@ private int fillToStart(int leadingEdge, LayoutState state) {
LayoutParams anchorParams = (LayoutParams) anchor.getLayoutParams();
final int sfp = anchorParams.getTestedFirstPosition();
final View first = getHeaderOrFirstViewForSection(sfp, Direction.START, state);
final SectionData sd = new SectionData(this, first);
final SectionData sd = getSectionData(sfp, first);

final SectionLayoutManager slm = getSlm(sd);

Expand Down Expand Up @@ -1076,10 +1097,15 @@ private int getBorderLine(View anchorView, Direction direction) {
return borderline;
}

private SectionData getCachedSectionData(View child) {
LayoutParams params = (LayoutParams) child.getLayoutParams();
return mSectionDataCache.get(params.getTestedFirstPosition());
}

private int getDirectionToPosition(int targetPosition) {
SectionData sd = new SectionData(this, getChildAt(0));
final View startSectionFirstView = getSlm(sd)
.findFirstVisibleView(sd.firstPosition, true);
LayoutParams params = (LayoutParams) getChildAt(0).getLayoutParams();
final View startSectionFirstView = getSlm(params)
.findFirstVisibleView(params.getTestedFirstPosition(), true);
return targetPosition < getPosition(startSectionFirstView) ? -1 : 1;
}

Expand All @@ -1101,7 +1127,8 @@ private float getFractionOfContentAbove(RecyclerView.State state, boolean ignore
float height = getDecoratedMeasuredHeight(child);
fractionOffscreen = -top / height;
}
SectionData sd = new SectionData(this, child);

SectionData sd = getCachedSectionData(child);
if (sd.headerParams.isHeader && sd.headerParams.isHeaderInline()) {
// Header must not be stickied as it is not attached after section items.
return fractionOffscreen;
Expand All @@ -1113,7 +1140,7 @@ private float getFractionOfContentAbove(RecyclerView.State state, boolean ignore
for (int i = 1; i < getChildCount(); i++) {
child = getChildAt(i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (!sd.sameSectionManager(lp)) {
if (lp.getTestedFirstPosition() != sd.firstPosition) {
break;
}

Expand Down Expand Up @@ -1152,7 +1179,7 @@ private float getFractionOfContentBelow(RecyclerView.State state, boolean ignore
final int anchorPosition = getPosition(child);
int countAfter = 0;

SectionData sd = new SectionData(this, child);
SectionData sd = getCachedSectionData(child);

float fractionOffscreen = 0;
int lastPosition = -1;
Expand All @@ -1161,7 +1188,7 @@ private float getFractionOfContentBelow(RecyclerView.State state, boolean ignore
for (int i = 1; i <= getChildCount(); i++) {
child = getChildAt(getChildCount() - i);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (!sd.sameSectionManager(lp)) {
if (lp.getTestedFirstPosition() != sd.firstPosition) {
break;
}

Expand Down Expand Up @@ -1301,7 +1328,7 @@ private int layoutChildren(int anchorPosition, int borderLine, LayoutState state
measureHeader(first.view);
state.cacheView(sfp, first.view);

final SectionData sd = new SectionData(this, first.view);
final SectionData sd = getSectionData(sfp, first.view);

final SectionLayoutManager slm = getSlm(sd);
// Layout header
Expand Down Expand Up @@ -1618,22 +1645,23 @@ private int updateHeaderForStart(View header, int leadingEdge, int markerLine, S
}

private void updateHeaderForTrimFromStart(View header) {
SectionData sd = new SectionData(this, header);
if (!sd.headerParams.isHeaderSticky()) {
LayoutParams params = (LayoutParams) header.getLayoutParams();
if (!params.isHeaderSticky()) {
return;
}

final int slp = findLastIndexForSection(sd.firstPosition);
int sfp = params.getTestedFirstPosition();
final int slp = findLastIndexForSection(sfp);
if (slp == -1) {
return;
}

SectionLayoutManager slm = getSlm(sd);
final int sectionBottom = slm.getLowestEdge(sd.firstPosition, slp, getHeight());
final int sectionTop = slm.getHighestEdge(sd.firstPosition, 0, 0);
SectionLayoutManager slm = getSlm(params);
final int sectionBottom = slm.getLowestEdge(sfp, slp, getHeight());
final int sectionTop = slm.getHighestEdge(sfp, 0, 0);

final int height = getDecoratedMeasuredHeight(header);
if ((sd.headerParams.isHeaderInline() && !sd.headerParams.isHeaderOverlay())
if ((params.isHeaderInline() && !params.isHeaderOverlay())
|| (sectionBottom - sectionTop) > height) {
final int left = getDecoratedLeft(header);
final int right = getDecoratedRight(header);
Expand Down

0 comments on commit b9d57de

Please sign in to comment.