PagerSnapHelper.java revision 396f55a04df1b3fdfa3e7192ce14f050aed9a6d9
1849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas/* 2849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * Copyright (C) 2016 The Android Open Source Project 3849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * 4849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * Licensed under the Apache License, Version 2.0 (the "License"); 5849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * you may not use this file except in compliance with the License. 6849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * You may obtain a copy of the License at 7849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * 8849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * http://www.apache.org/licenses/LICENSE-2.0 9849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * 10849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * Unless required by applicable law or agreed to in writing, software 11849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * distributed under the License is distributed on an "AS IS" BASIS, 12849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * See the License for the specific language governing permissions and 14849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * limitations under the License. 15849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas */ 16849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 17849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikaspackage android.support.v7.widget; 18849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 19849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikasimport android.graphics.PointF; 20849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikasimport android.support.annotation.NonNull; 21849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikasimport android.support.annotation.Nullable; 22396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikasimport android.util.DisplayMetrics; 23849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikasimport android.view.View; 24849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 25849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas/** 26849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * Implementation of the {@link SnapHelper} supporting pager style snapping in either vertical or 27849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * horizontal orientation. 28396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas * 29396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas * <p> 30396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas * 31396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas * PagerSnapHelper can help achieve a similar behavior to {@link android.support.v4.view.ViewPager}. 32396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas * Set both {@link RecyclerView} and {@link android.support.v7.widget.RecyclerView.Adapter} to have 33396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas * MATCH_PARENT height and width and then attach PagerSnapHelper to the {@link RecyclerView} using 34396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas * {@link #attachToRecyclerView(RecyclerView)}. 35849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas */ 36849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikaspublic class PagerSnapHelper extends SnapHelper { 37396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas private static final int MAX_SCROLL_ON_FLING_DURATION = 100; // ms 38396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas 39849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas // Orientation helpers are lazily created per LayoutManager. 40849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Nullable 41849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas private OrientationHelper mVerticalHelper; 42849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Nullable 43849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas private OrientationHelper mHorizontalHelper; 44849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 45849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Nullable 46849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Override 47849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, 48849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @NonNull View targetView) { 49849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int[] out = new int[2]; 50849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (layoutManager.canScrollHorizontally()) { 51849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas out[0] = distanceToCenter(layoutManager, targetView, 52849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas getHorizontalHelper(layoutManager)); 53849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } else { 54849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas out[0] = 0; 55849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 56849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 57849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (layoutManager.canScrollVertically()) { 58849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas out[1] = distanceToCenter(layoutManager, targetView, 59849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas getVerticalHelper(layoutManager)); 60849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } else { 61849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas out[1] = 0; 62849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 63849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return out; 64849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 65849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 66849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Nullable 67849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Override 68849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas public View findSnapView(RecyclerView.LayoutManager layoutManager) { 69849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (layoutManager.canScrollVertically()) { 70849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return findCenterView(layoutManager, getVerticalHelper(layoutManager)); 71849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } else if (layoutManager.canScrollHorizontally()) { 72849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return findCenterView(layoutManager, getHorizontalHelper(layoutManager)); 73849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 74849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return null; 75849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 76849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 77849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Override 78849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, 79849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int velocityY) { 80849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas final int itemCount = layoutManager.getItemCount(); 81849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (itemCount == 0) { 82849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return RecyclerView.NO_POSITION; 83849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 84849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 85849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas View mStartMostChildView = null; 86849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (layoutManager.canScrollVertically()) { 87849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas mStartMostChildView = findStartView(layoutManager, getVerticalHelper(layoutManager)); 88849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } else if (layoutManager.canScrollHorizontally()) { 89849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas mStartMostChildView = findStartView(layoutManager, getHorizontalHelper(layoutManager)); 90849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 91849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 92849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (mStartMostChildView == null) { 93849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return RecyclerView.NO_POSITION; 94849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 95849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas final int centerPosition = layoutManager.getPosition(mStartMostChildView); 96849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (centerPosition == RecyclerView.NO_POSITION) { 97849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return RecyclerView.NO_POSITION; 98849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 99849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 100849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas final boolean forwardDirection; 101849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (layoutManager.canScrollHorizontally()) { 102849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas forwardDirection = velocityX > 0; 103849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } else { 104849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas forwardDirection = velocityY > 0; 105849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 106849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas boolean reverseLayout = false; 107849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if ((layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)) { 108849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas RecyclerView.SmoothScroller.ScrollVectorProvider vectorProvider = 109849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas (RecyclerView.SmoothScroller.ScrollVectorProvider) layoutManager; 110849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas PointF vectorForEnd = vectorProvider.computeScrollVectorForPosition(itemCount - 1); 111849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (vectorForEnd != null) { 112849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas reverseLayout = vectorForEnd.x < 0 || vectorForEnd.y < 0; 113849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 114849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 115849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return reverseLayout 116849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas ? (forwardDirection ? centerPosition - 1 : centerPosition) 117849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas : (forwardDirection ? centerPosition + 1 : centerPosition); 118849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 119849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 120396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas @Override 121396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas protected LinearSmoothScroller createSnapScroller(RecyclerView.LayoutManager layoutManager) { 122396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas if (!(layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)) { 123396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas return null; 124396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas } 125396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas return new LinearSmoothScroller(mRecyclerView.getContext()) { 126396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas @Override 127396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas protected void onTargetFound(View targetView, RecyclerView.State state, Action action) { 128396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas int[] snapDistances = calculateDistanceToFinalSnap(mRecyclerView.getLayoutManager(), 129396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas targetView); 130396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas final int dx = snapDistances[0]; 131396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas final int dy = snapDistances[1]; 132396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas final int time = calculateTimeForDeceleration(Math.max(Math.abs(dx), Math.abs(dy))); 133396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas if (time > 0) { 134396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas action.update(dx, dy, time, mDecelerateInterpolator); 135396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas } 136396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas } 137396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas 138396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas @Override 139396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { 140396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas return MILLISECONDS_PER_INCH / displayMetrics.densityDpi; 141396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas } 142396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas 143396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas @Override 144396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas protected int calculateTimeForScrolling(int dx) { 145396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas return Math.min(MAX_SCROLL_ON_FLING_DURATION, super.calculateTimeForScrolling(dx)); 146396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas } 147396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas }; 148396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas } 149396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas 150849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas private int distanceToCenter(@NonNull RecyclerView.LayoutManager layoutManager, 151849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @NonNull View targetView, OrientationHelper helper) { 152849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas final int childCenter = helper.getDecoratedStart(targetView) 153849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas + (helper.getDecoratedMeasurement(targetView) / 2); 154849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas final int containerCenter; 155849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (layoutManager.getClipToPadding()) { 156849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas containerCenter = helper.getStartAfterPadding() + helper.getTotalSpace() / 2; 157849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } else { 158849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas containerCenter = helper.getEnd() / 2; 159849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 160849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return childCenter - containerCenter; 161849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 162849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 163849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas /** 164849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * Return the child view that is currently closest to the center of this parent. 165849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * 166849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * @param layoutManager The {@link RecyclerView.LayoutManager} associated with the attached 167849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * {@link RecyclerView}. 168849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * @param helper The relevant {@link OrientationHelper} for the attached {@link RecyclerView}. 169849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * 170849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * @return the child view that is currently closest to the center of this parent. 171849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas */ 172849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Nullable 173849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas private View findCenterView(RecyclerView.LayoutManager layoutManager, 174849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas OrientationHelper helper) { 175849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int childCount = layoutManager.getChildCount(); 176849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (childCount == 0) { 177849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return null; 178849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 179849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 180849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas View closestChild = null; 181849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas final int center; 182849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (layoutManager.getClipToPadding()) { 183849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas center = helper.getStartAfterPadding() + helper.getTotalSpace() / 2; 184849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } else { 185849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas center = helper.getEnd() / 2; 186849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 187849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int absClosest = Integer.MAX_VALUE; 188849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 189849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas for (int i = 0; i < childCount; i++) { 190849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas final View child = layoutManager.getChildAt(i); 191849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int childCenter = helper.getDecoratedStart(child) 192849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas + (helper.getDecoratedMeasurement(child) / 2); 193849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int absDistance = Math.abs(childCenter - center); 194849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 195849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas /** if child center is closer than previous closest, set it as closest **/ 196849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (absDistance < absClosest) { 197849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas absClosest = absDistance; 198849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas closestChild = child; 199849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 200849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 201849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return closestChild; 202849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 203849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 204849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas /** 205849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * Return the child view that is currently closest to the start of this parent. 206849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * 207849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * @param layoutManager The {@link RecyclerView.LayoutManager} associated with the attached 208849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * {@link RecyclerView}. 209849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * @param helper The relevant {@link OrientationHelper} for the attached {@link RecyclerView}. 210849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * 211849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * @return the child view that is currently closest to the start of this parent. 212849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas */ 213849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Nullable 214849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas private View findStartView(RecyclerView.LayoutManager layoutManager, 215849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas OrientationHelper helper) { 216849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int childCount = layoutManager.getChildCount(); 217849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (childCount == 0) { 218849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return null; 219849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 220849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 221849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas View closestChild = null; 222849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int startest = Integer.MAX_VALUE; 223849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 224849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas for (int i = 0; i < childCount; i++) { 225849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas final View child = layoutManager.getChildAt(i); 226849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int childStart = helper.getDecoratedStart(child); 227849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 228849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas /** if child is more to start than previous closest, set it as closest **/ 229849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (childStart < startest) { 230849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas startest = childStart; 231849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas closestChild = child; 232849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 233849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 234849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return closestChild; 235849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 236849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 237849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @NonNull 238849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas private OrientationHelper getVerticalHelper(@NonNull RecyclerView.LayoutManager layoutManager) { 239849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (mVerticalHelper == null || mVerticalHelper.mLayoutManager != layoutManager) { 240849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager); 241849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 242849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return mVerticalHelper; 243849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 244849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 245849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @NonNull 246849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas private OrientationHelper getHorizontalHelper( 247849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @NonNull RecyclerView.LayoutManager layoutManager) { 248849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (mHorizontalHelper == null || mHorizontalHelper.mLayoutManager != layoutManager) { 249849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager); 250849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 251849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return mHorizontalHelper; 252849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 253849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas} 254