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

View file

@ -157,6 +157,22 @@ public class BetterLinearLayoutManager extends LinearLayoutManager implements
*/
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.
// This should only be used used transiently and should not be used to retain any state over
// time.
@ -852,8 +868,16 @@ public class BetterLinearLayoutManager extends LinearLayoutManager implements
Log.d(TAG, "deciding anchor info for fresh state");
}
anchorInfo.assignCoordinateFromPadding();
if (mPreferredAnchorPosition >= 0) {
if (mPreferredAnchorPosition < state.getItemCount()) {
anchorInfo.mPosition = mPreferredAnchorPosition;
} else {
anchorInfo.mPosition = state.getItemCount() - 1;
}
} else {
anchorInfo.mPosition = mStackFromEnd ? state.getItemCount() - 1 : 0;
}
}
/**
* Finds an anchor child from existing Views. Most of the time, this is the view closest to
@ -1878,12 +1902,26 @@ public class BetterLinearLayoutManager extends LinearLayoutManager implements
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 boundsEnd = mOrientationHelper.getEndAfterPadding();
final int shouldCover = (int) ((boundsEnd - boundsStart) * mPreferredAnchorPlacement);
View invalidMatch = null;
View bestFirstFind = null;
View bestSecondFind = null;
View bestFind = null;
for (int i = start; i != end; i += diff) {
@ -1922,6 +1960,22 @@ public class BetterLinearLayoutManager extends LinearLayoutManager implements
bestSecondFind = view;
}
}
} else {
if (mCareAboutAnchorPlacement) {
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;
@ -1929,6 +1983,12 @@ public class BetterLinearLayoutManager extends LinearLayoutManager implements
}
}
}
}
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:
// 1. bestSecondFind
@ -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
* space.