From eddd0a185e200bc28a621b8e3171c64d3bb9d2cf Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Wed, 27 Oct 2021 17:30:55 +0200 Subject: [PATCH] Allow to better control anchors in BetterLinearLayoutManager Change-Id: Ic91a2cfbf53e5f59f395467bd020b970626d2a55 --- .../widget/BetterLinearLayoutManager.java | 92 ++++++++++++++++++- 1 file changed, 88 insertions(+), 4 deletions(-) diff --git a/vector/src/main/java/de/spiritcroc/recyclerview/widget/BetterLinearLayoutManager.java b/vector/src/main/java/de/spiritcroc/recyclerview/widget/BetterLinearLayoutManager.java index 6e97a2b5a3..8aa21bc698 100644 --- a/vector/src/main/java/de/spiritcroc/recyclerview/widget/BetterLinearLayoutManager.java +++ b/vector/src/main/java/de/spiritcroc/recyclerview/widget/BetterLinearLayoutManager.java @@ -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,7 +868,15 @@ public class BetterLinearLayoutManager extends LinearLayoutManager implements Log.d(TAG, "deciding anchor info for fresh state"); } 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(); + // 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) { @@ -1923,13 +1961,35 @@ public class BetterLinearLayoutManager extends LinearLayoutManager implements } } } else { - // We found an in bounds item, greedily return it. - return view; + 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; + } } } } } + 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 // 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 * space. @@ -2620,4 +2704,4 @@ public class BetterLinearLayoutManager extends LinearLayoutManager implements mFocusable = false; } } -} +} \ No newline at end of file