PagerSnapHelper.java revision 4e05ba710eb6a2aea1e5f91eecb730e1931b3f40
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}. 324e05ba710eb6a2aea1e5f91eecb730e1931b3f40Aurimas Liutikas * Set both {@link RecyclerView} and the items of the 334e05ba710eb6a2aea1e5f91eecb730e1931b3f40Aurimas Liutikas * {@link android.support.v7.widget.RecyclerView.Adapter} to have 344e05ba710eb6a2aea1e5f91eecb730e1931b3f40Aurimas Liutikas * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} height and width and then attach 354e05ba710eb6a2aea1e5f91eecb730e1931b3f40Aurimas Liutikas * PagerSnapHelper to the {@link RecyclerView} using {@link #attachToRecyclerView(RecyclerView)}. 36849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas */ 37849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikaspublic class PagerSnapHelper extends SnapHelper { 38396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas private static final int MAX_SCROLL_ON_FLING_DURATION = 100; // ms 39396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas 40849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas // Orientation helpers are lazily created per LayoutManager. 41849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Nullable 42849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas private OrientationHelper mVerticalHelper; 43849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Nullable 44849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas private OrientationHelper mHorizontalHelper; 45849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 46849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Nullable 47849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Override 48849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, 49849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @NonNull View targetView) { 50849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int[] out = new int[2]; 51849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (layoutManager.canScrollHorizontally()) { 52849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas out[0] = distanceToCenter(layoutManager, targetView, 53849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas getHorizontalHelper(layoutManager)); 54849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } else { 55849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas out[0] = 0; 56849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 57849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 58849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (layoutManager.canScrollVertically()) { 59849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas out[1] = distanceToCenter(layoutManager, targetView, 60849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas getVerticalHelper(layoutManager)); 61849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } else { 62849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas out[1] = 0; 63849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 64849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return out; 65849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 66849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 67849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Nullable 68849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Override 69849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas public View findSnapView(RecyclerView.LayoutManager layoutManager) { 70849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (layoutManager.canScrollVertically()) { 71849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return findCenterView(layoutManager, getVerticalHelper(layoutManager)); 72849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } else if (layoutManager.canScrollHorizontally()) { 73849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return findCenterView(layoutManager, getHorizontalHelper(layoutManager)); 74849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 75849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return null; 76849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 77849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 78849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Override 79849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, 80849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int velocityY) { 81849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas final int itemCount = layoutManager.getItemCount(); 82849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (itemCount == 0) { 83849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return RecyclerView.NO_POSITION; 84849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 85849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 86849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas View mStartMostChildView = null; 87849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (layoutManager.canScrollVertically()) { 88849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas mStartMostChildView = findStartView(layoutManager, getVerticalHelper(layoutManager)); 89849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } else if (layoutManager.canScrollHorizontally()) { 90849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas mStartMostChildView = findStartView(layoutManager, getHorizontalHelper(layoutManager)); 91849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 92849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 93849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (mStartMostChildView == null) { 94849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return RecyclerView.NO_POSITION; 95849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 96849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas final int centerPosition = layoutManager.getPosition(mStartMostChildView); 97849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (centerPosition == RecyclerView.NO_POSITION) { 98849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return RecyclerView.NO_POSITION; 99849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 100849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 101849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas final boolean forwardDirection; 102849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (layoutManager.canScrollHorizontally()) { 103849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas forwardDirection = velocityX > 0; 104849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } else { 105849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas forwardDirection = velocityY > 0; 106849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 107849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas boolean reverseLayout = false; 108849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if ((layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)) { 109849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas RecyclerView.SmoothScroller.ScrollVectorProvider vectorProvider = 110849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas (RecyclerView.SmoothScroller.ScrollVectorProvider) layoutManager; 111849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas PointF vectorForEnd = vectorProvider.computeScrollVectorForPosition(itemCount - 1); 112849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (vectorForEnd != null) { 113849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas reverseLayout = vectorForEnd.x < 0 || vectorForEnd.y < 0; 114849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 115849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 116849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return reverseLayout 117849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas ? (forwardDirection ? centerPosition - 1 : centerPosition) 118849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas : (forwardDirection ? centerPosition + 1 : centerPosition); 119849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 120849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 121396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas @Override 122396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas protected LinearSmoothScroller createSnapScroller(RecyclerView.LayoutManager layoutManager) { 123396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas if (!(layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)) { 124396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas return null; 125396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas } 126396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas return new LinearSmoothScroller(mRecyclerView.getContext()) { 127396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas @Override 128396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas protected void onTargetFound(View targetView, RecyclerView.State state, Action action) { 129396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas int[] snapDistances = calculateDistanceToFinalSnap(mRecyclerView.getLayoutManager(), 130396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas targetView); 131396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas final int dx = snapDistances[0]; 132396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas final int dy = snapDistances[1]; 133396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas final int time = calculateTimeForDeceleration(Math.max(Math.abs(dx), Math.abs(dy))); 134396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas if (time > 0) { 135396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas action.update(dx, dy, time, mDecelerateInterpolator); 136396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas } 137396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas } 138396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas 139396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas @Override 140396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { 141396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas return MILLISECONDS_PER_INCH / displayMetrics.densityDpi; 142396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas } 143396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas 144396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas @Override 145396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas protected int calculateTimeForScrolling(int dx) { 146396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas return Math.min(MAX_SCROLL_ON_FLING_DURATION, super.calculateTimeForScrolling(dx)); 147396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas } 148396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas }; 149396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas } 150396f55a04df1b3fdfa3e7192ce14f050aed9a6d9Aurimas Liutikas 151849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas private int distanceToCenter(@NonNull RecyclerView.LayoutManager layoutManager, 152849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @NonNull View targetView, OrientationHelper helper) { 153849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas final int childCenter = helper.getDecoratedStart(targetView) 154849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas + (helper.getDecoratedMeasurement(targetView) / 2); 155849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas final int containerCenter; 156849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (layoutManager.getClipToPadding()) { 157849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas containerCenter = helper.getStartAfterPadding() + helper.getTotalSpace() / 2; 158849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } else { 159849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas containerCenter = helper.getEnd() / 2; 160849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 161849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return childCenter - containerCenter; 162849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 163849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 164849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas /** 165849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * Return the child view that is currently closest to the center of this parent. 166849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * 167849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * @param layoutManager The {@link RecyclerView.LayoutManager} associated with the attached 168849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * {@link RecyclerView}. 169849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * @param helper The relevant {@link OrientationHelper} for the attached {@link RecyclerView}. 170849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * 171849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * @return the child view that is currently closest to the center of this parent. 172849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas */ 173849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Nullable 174849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas private View findCenterView(RecyclerView.LayoutManager layoutManager, 175849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas OrientationHelper helper) { 176849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int childCount = layoutManager.getChildCount(); 177849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (childCount == 0) { 178849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return null; 179849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 180849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 181849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas View closestChild = null; 182849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas final int center; 183849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (layoutManager.getClipToPadding()) { 184849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas center = helper.getStartAfterPadding() + helper.getTotalSpace() / 2; 185849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } else { 186849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas center = helper.getEnd() / 2; 187849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 188849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int absClosest = Integer.MAX_VALUE; 189849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 190849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas for (int i = 0; i < childCount; i++) { 191849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas final View child = layoutManager.getChildAt(i); 192849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int childCenter = helper.getDecoratedStart(child) 193849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas + (helper.getDecoratedMeasurement(child) / 2); 194849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int absDistance = Math.abs(childCenter - center); 195849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 196849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas /** if child center is closer than previous closest, set it as closest **/ 197849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (absDistance < absClosest) { 198849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas absClosest = absDistance; 199849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas closestChild = child; 200849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 201849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 202849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return closestChild; 203849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 204849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 205849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas /** 206849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * Return the child view that is currently closest to the start of this parent. 207849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * 208849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * @param layoutManager The {@link RecyclerView.LayoutManager} associated with the attached 209849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * {@link RecyclerView}. 210849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * @param helper The relevant {@link OrientationHelper} for the attached {@link RecyclerView}. 211849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * 212849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas * @return the child view that is currently closest to the start of this parent. 213849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas */ 214849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @Nullable 215849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas private View findStartView(RecyclerView.LayoutManager layoutManager, 216849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas OrientationHelper helper) { 217849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int childCount = layoutManager.getChildCount(); 218849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (childCount == 0) { 219849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return null; 220849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 221849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 222849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas View closestChild = null; 223849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int startest = Integer.MAX_VALUE; 224849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 225849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas for (int i = 0; i < childCount; i++) { 226849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas final View child = layoutManager.getChildAt(i); 227849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas int childStart = helper.getDecoratedStart(child); 228849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 229849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas /** if child is more to start than previous closest, set it as closest **/ 230849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (childStart < startest) { 231849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas startest = childStart; 232849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas closestChild = child; 233849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 234849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 235849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return closestChild; 236849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 237849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 238849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @NonNull 239849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas private OrientationHelper getVerticalHelper(@NonNull RecyclerView.LayoutManager layoutManager) { 240849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (mVerticalHelper == null || mVerticalHelper.mLayoutManager != layoutManager) { 241849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager); 242849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 243849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return mVerticalHelper; 244849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 245849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas 246849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @NonNull 247849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas private OrientationHelper getHorizontalHelper( 248849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas @NonNull RecyclerView.LayoutManager layoutManager) { 249849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas if (mHorizontalHelper == null || mHorizontalHelper.mLayoutManager != layoutManager) { 250849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager); 251849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 252849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas return mHorizontalHelper; 253849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas } 254849542dfdc5e83411c8b959251eb6f2a1556fc9dAurimas Liutikas} 255