diff --git a/app/src/main/java/org/fdroid/fdroid/views/LinearLayoutManagerSnapHelper.java b/app/src/main/java/org/fdroid/fdroid/views/LinearLayoutManagerSnapHelper.java index ebbecf2eb..a4dc2fc12 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/LinearLayoutManagerSnapHelper.java +++ b/app/src/main/java/org/fdroid/fdroid/views/LinearLayoutManagerSnapHelper.java @@ -1,5 +1,6 @@ package org.fdroid.fdroid.views; +import android.support.annotation.NonNull; import android.support.v4.view.ViewCompat; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearSnapHelper; @@ -11,6 +12,9 @@ import static android.support.v7.widget.RecyclerView.NO_POSITION; public class LinearLayoutManagerSnapHelper extends LinearSnapHelper { + private View mLastSavedTarget; + private int mLastSavedDistance; + public interface LinearSnapHelperListener { /** * Tells the listener that we have selected a view to snap to. @@ -36,29 +40,56 @@ public class LinearLayoutManagerSnapHelper extends LinearSnapHelper { @Override public View findSnapView(RecyclerView.LayoutManager layoutManager) { View snappedView = super.findSnapView(layoutManager); - if (layoutManager.canScrollHorizontally()) { + if (snappedView != null && layoutManager.canScrollHorizontally()) { if (layoutManager instanceof LinearLayoutManager) { + mLastSavedTarget = null; + + int distSnap = super.calculateDistanceToFinalSnap(layoutManager, snappedView)[0]; + int firstChild = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition(); int lastChild = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition(); - if (firstChild == 0) { - View child = layoutManager.findViewByPosition(firstChild); - if (mOrientationHelper.getDecoratedEnd(child) >= mOrientationHelper.getDecoratedMeasurement(child) / 2 - && mOrientationHelper.getDecoratedEnd(child) > 0) { - int dist1 = super.calculateDistanceToFinalSnap(layoutManager, snappedView)[0]; - int dist2 = mOrientationHelper.getDecoratedStart(child); - if (Math.abs(dist1) > Math.abs(dist2)) { - snappedView = child; + + int idxSnap = -1; + for (int i = firstChild; i <= lastChild; i++) { + View view = ((LinearLayoutManager) layoutManager).findViewByPosition(i); + if (view == snappedView) { + idxSnap = i; + break; + } + } + + int snapPositionFirst = mOrientationHelper.getDecoratedMeasurement(((LinearLayoutManager) layoutManager).findViewByPosition(firstChild)) / 2; + int snapPositionLast = mOrientationHelper.getTotalSpace() - mOrientationHelper.getDecoratedMeasurement(((LinearLayoutManager) layoutManager).findViewByPosition(lastChild)) / 2; + + int centerSnapPosition = mOrientationHelper.getTotalSpace() / 2; + + if (idxSnap != -1) { + int currentSmallestDistance = Integer.MAX_VALUE; + View currentSmallestDistanceView = null; + for (int i = firstChild; i <= lastChild; i++) { + View view = ((LinearLayoutManager) layoutManager).findViewByPosition(i); + if (i < idxSnap && firstChild == 0) { + int snapPosition = snapPositionFirst + (i - firstChild) * (centerSnapPosition - snapPositionFirst) / (idxSnap - firstChild); + int viewPosition = view.getLeft() + view.getWidth() / 2; + int dist = snapPosition - viewPosition; + if (Math.abs(dist) < Math.abs(currentSmallestDistance) || (Math.abs(dist) == Math.abs(currentSmallestDistance) && distSnap > 0)) { + currentSmallestDistance = dist; + currentSmallestDistanceView = view; + } + } else if (i > idxSnap && lastChild == (mLlm.getItemCount() - 1)) { + int snapPosition = snapPositionLast - (lastChild - i) * (snapPositionLast - centerSnapPosition) / (lastChild - idxSnap); + int viewPosition = view.getLeft() + view.getWidth() / 2; + int dist = snapPosition - viewPosition; + if (Math.abs(dist) < Math.abs(currentSmallestDistance) || (Math.abs(dist) == Math.abs(currentSmallestDistance) && distSnap < 0)) { + currentSmallestDistance = dist; + currentSmallestDistanceView = view; + } } } - } else if (lastChild == (mLlm.getItemCount() - 1)) { - View child = layoutManager.findViewByPosition(lastChild); - if (mOrientationHelper.getDecoratedStart(child) < mOrientationHelper.getTotalSpace() - mOrientationHelper.getDecoratedMeasurement(child) / 2 - && mOrientationHelper.getDecoratedStart(child) < mOrientationHelper.getTotalSpace()) { - int dist1 = super.calculateDistanceToFinalSnap(layoutManager, snappedView)[0]; - int dist2 = mOrientationHelper.getTotalSpace() - mOrientationHelper.getDecoratedEnd(child); - if (Math.abs(dist1) > Math.abs(dist2)) { - snappedView = child; - } + if (Math.abs(distSnap) > Math.abs(currentSmallestDistance)) { + snappedView = currentSmallestDistanceView; + mLastSavedTarget = currentSmallestDistanceView; + mLastSavedDistance = -currentSmallestDistance; } } } @@ -71,4 +102,15 @@ public class LinearLayoutManagerSnapHelper extends LinearSnapHelper { } return snappedView; } + + @Override + public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) { + if (targetView == mLastSavedTarget) { + int[] out = new int[2]; + out[0] = mLastSavedDistance; + out[1] = 0; + return out; + } + return super.calculateDistanceToFinalSnap(layoutManager, targetView); + } }