Allow to better control anchors in BetterLinearLayoutManager

Change-Id: Ic91a2cfbf53e5f59f395467bd020b970626d2a55
This commit is contained in:
SpiritCroc 2021-10-27 17:30:55 +02:00
parent 2d63dbbf12
commit eddd0a185e
1 changed files with 88 additions and 4 deletions

View File

@ -157,6 +157,22 @@ public class BetterLinearLayoutManager extends LinearLayoutManager implements
*/ */
private int mInitialPrefetchItemCount = 2; private int mInitialPrefetchItemCount = 2;
/**
* The position to use as anchor.
*/
private int mPreferredAnchorPosition = -1;
/**
* Whether to care about the placement of the anchor view, i.e., whether to use mPreferredAnchorPlacement.
*/
private boolean mCareAboutAnchorPlacement = false;
/**
* The placement where to look for anchor views, relative to the visible bounds.
* Should usually be within 0f - 1f.
*/
private float mPreferredAnchorPlacement = 0.5f;
// Reusable int array to be passed to method calls that mutate it in order to "return" two ints. // Reusable int array to be passed to method calls that mutate it in order to "return" two ints.
// This should only be used used transiently and should not be used to retain any state over // This should only be used used transiently and should not be used to retain any state over
// time. // time.
@ -852,7 +868,15 @@ public class BetterLinearLayoutManager extends LinearLayoutManager implements
Log.d(TAG, "deciding anchor info for fresh state"); Log.d(TAG, "deciding anchor info for fresh state");
} }
anchorInfo.assignCoordinateFromPadding(); anchorInfo.assignCoordinateFromPadding();
anchorInfo.mPosition = mStackFromEnd ? state.getItemCount() - 1 : 0; if (mPreferredAnchorPosition >= 0) {
if (mPreferredAnchorPosition < state.getItemCount()) {
anchorInfo.mPosition = mPreferredAnchorPosition;
} else {
anchorInfo.mPosition = state.getItemCount() - 1;
}
} else {
anchorInfo.mPosition = mStackFromEnd ? state.getItemCount() - 1 : 0;
}
} }
/** /**
@ -1878,12 +1902,26 @@ public class BetterLinearLayoutManager extends LinearLayoutManager implements
int itemCount = state.getItemCount(); int itemCount = state.getItemCount();
// Prefer exact matches to anything else if possible
if (mPreferredAnchorPosition >= 0 && mPreferredAnchorPosition < itemCount) {
for (int i = start; i != end; i += diff) {
final View view = getChildAt(i);
final int position = getPosition(view);
if (position == mPreferredAnchorPosition &&
!((RecyclerView.LayoutParams) view.getLayoutParams()).isItemRemoved()) {
return view;
}
}
}
final int boundsStart = mOrientationHelper.getStartAfterPadding(); final int boundsStart = mOrientationHelper.getStartAfterPadding();
final int boundsEnd = mOrientationHelper.getEndAfterPadding(); final int boundsEnd = mOrientationHelper.getEndAfterPadding();
final int shouldCover = (int) ((boundsEnd - boundsStart) * mPreferredAnchorPlacement);
View invalidMatch = null; View invalidMatch = null;
View bestFirstFind = null; View bestFirstFind = null;
View bestSecondFind = null; View bestSecondFind = null;
View bestFind = null;
for (int i = start; i != end; i += diff) { for (int i = start; i != end; i += diff) {
@ -1923,13 +1961,35 @@ public class BetterLinearLayoutManager extends LinearLayoutManager implements
} }
} }
} else { } else {
// We found an in bounds item, greedily return it. if (mCareAboutAnchorPlacement) {
return view; if (bestFind == null) {
bestFind = view;
}
if (layoutFromEnd) {
if (childStart < shouldCover) {
// Won't get better than this
return view;
}
} else {
if (childEnd > shouldCover) {
// Won't get better than this
return view;
}
}
} else {
// We found an in bounds item, greedily return it.
return view;
}
} }
} }
} }
} }
if (bestFind != null) {
// Upstream would have returned this immediately
return bestFind;
}
// We didn't find an in bounds item so we will settle for an item in this order: // We didn't find an in bounds item so we will settle for an item in this order:
// 1. bestSecondFind // 1. bestSecondFind
// 2. bestFirstFind // 2. bestFirstFind
@ -2245,6 +2305,30 @@ public class BetterLinearLayoutManager extends LinearLayoutManager implements
} }
} }
/**
* Set the position to use as anchor. Use -1 to not use a fixed anchor position.
*/
public void setPreferredAnchorPosition(int anchorPosition) {
mPreferredAnchorPosition = anchorPosition;
}
/**
* Set the placement where to look for anchor views, relative to the visible bounds.
* Should usually be within 0f - 1f.
*/
public void setPreferredAnchorPlacement(float placement) {
mPreferredAnchorPlacement = placement;
mCareAboutAnchorPlacement = true;
}
/**
* Disable fixing a certain area for views.
* Reverts the effect of {@link #setPreferredAnchorPlacement(float)}.
*/
public void disablePreferredAnchorPlacement() {
mCareAboutAnchorPlacement = false;
}
/** /**
* Helper class that keeps temporary state while {LayoutManager} is filling out the empty * Helper class that keeps temporary state while {LayoutManager} is filling out the empty
* space. * space.