1c587f7dba5a337169e854e235da59f595255d6ccAga Madurska/* 2c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * Copyright (C) 2016 The Android Open Source Project 3c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * 4c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * Licensed under the Apache License, Version 2.0 (the "License"); 5c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * you may not use this file except in compliance with the License. 6c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * You may obtain a copy of the License at 7c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * 8c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * http://www.apache.org/licenses/LICENSE-2.0 9c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * 10c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * Unless required by applicable law or agreed to in writing, software 11c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * distributed under the License is distributed on an "AS IS" BASIS, 12c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * See the License for the specific languag`e governing permissions and 14c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * limitations under the License. 15c587f7dba5a337169e854e235da59f595255d6ccAga Madurska */ 16c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 17c587f7dba5a337169e854e235da59f595255d6ccAga Madurskapackage android.support.v7.widget; 18c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 19c587f7dba5a337169e854e235da59f595255d6ccAga Madurskaimport android.graphics.PointF; 20c587f7dba5a337169e854e235da59f595255d6ccAga Madurskaimport android.support.annotation.NonNull; 21c587f7dba5a337169e854e235da59f595255d6ccAga Madurskaimport android.support.annotation.Nullable; 22c587f7dba5a337169e854e235da59f595255d6ccAga Madurskaimport android.view.View; 23c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 24c587f7dba5a337169e854e235da59f595255d6ccAga Madurska/** 25c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * Implementation of the {@link SnapHelper} supporting snapping in either vertical or horizontal 26c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * orientation. 27c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * <p> 28c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * The implementation will snap the center of the target child view to the center of 29c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * the attached {@link RecyclerView}. If you intend to change this behavior then override 30c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * {@link SnapHelper#calculateDistanceToFinalSnap}. 31c587f7dba5a337169e854e235da59f595255d6ccAga Madurska */ 32c587f7dba5a337169e854e235da59f595255d6ccAga Madurskapublic class LinearSnapHelper extends SnapHelper { 33c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 34c587f7dba5a337169e854e235da59f595255d6ccAga Madurska private static final float INVALID_DISTANCE = 1f; 35c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 36c587f7dba5a337169e854e235da59f595255d6ccAga Madurska // Orientation helpers are lazily created per LayoutManager. 37c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @Nullable 38c587f7dba5a337169e854e235da59f595255d6ccAga Madurska private OrientationHelper mVerticalHelper; 39c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @Nullable 40c587f7dba5a337169e854e235da59f595255d6ccAga Madurska private OrientationHelper mHorizontalHelper; 41c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 42c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @Override 43c587f7dba5a337169e854e235da59f595255d6ccAga Madurska public int[] calculateDistanceToFinalSnap( 44c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) { 45c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int[] out = new int[2]; 46c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (layoutManager.canScrollHorizontally()) { 47c587f7dba5a337169e854e235da59f595255d6ccAga Madurska out[0] = distanceToCenter(layoutManager, targetView, 48c587f7dba5a337169e854e235da59f595255d6ccAga Madurska getHorizontalHelper(layoutManager)); 49c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } else { 50c587f7dba5a337169e854e235da59f595255d6ccAga Madurska out[0] = 0; 51c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 52c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 53c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (layoutManager.canScrollVertically()) { 54c587f7dba5a337169e854e235da59f595255d6ccAga Madurska out[1] = distanceToCenter(layoutManager, targetView, 55c587f7dba5a337169e854e235da59f595255d6ccAga Madurska getVerticalHelper(layoutManager)); 56c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } else { 57c587f7dba5a337169e854e235da59f595255d6ccAga Madurska out[1] = 0; 58c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 59c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return out; 60c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 61c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 62c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @Override 63c587f7dba5a337169e854e235da59f595255d6ccAga Madurska public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, 64c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int velocityY) { 65c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (!(layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)) { 66c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return RecyclerView.NO_POSITION; 67c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 68c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 69c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final int itemCount = layoutManager.getItemCount(); 70c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (itemCount == 0) { 71c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return RecyclerView.NO_POSITION; 72c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 73c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 74c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final View currentView = findSnapView(layoutManager); 75c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (currentView == null) { 76c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return RecyclerView.NO_POSITION; 77c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 78c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 79c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final int currentPosition = layoutManager.getPosition(currentView); 80c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (currentPosition == RecyclerView.NO_POSITION) { 81c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return RecyclerView.NO_POSITION; 82c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 83c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 84c587f7dba5a337169e854e235da59f595255d6ccAga Madurska RecyclerView.SmoothScroller.ScrollVectorProvider vectorProvider = 85c587f7dba5a337169e854e235da59f595255d6ccAga Madurska (RecyclerView.SmoothScroller.ScrollVectorProvider) layoutManager; 86c587f7dba5a337169e854e235da59f595255d6ccAga Madurska // deltaJumps sign comes from the velocity which may not match the order of children in 87c587f7dba5a337169e854e235da59f595255d6ccAga Madurska // the LayoutManager. To overcome this, we ask for a vector from the LayoutManager to 88c587f7dba5a337169e854e235da59f595255d6ccAga Madurska // get the direction. 89c587f7dba5a337169e854e235da59f595255d6ccAga Madurska PointF vectorForEnd = vectorProvider.computeScrollVectorForPosition(itemCount - 1); 90c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (vectorForEnd == null) { 91c587f7dba5a337169e854e235da59f595255d6ccAga Madurska // cannot get a vector for the given position. 92c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return RecyclerView.NO_POSITION; 93c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 94c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 95c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int vDeltaJump, hDeltaJump; 96c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (layoutManager.canScrollHorizontally()) { 97c587f7dba5a337169e854e235da59f595255d6ccAga Madurska hDeltaJump = estimateNextPositionDiffForFling(layoutManager, 98c587f7dba5a337169e854e235da59f595255d6ccAga Madurska getHorizontalHelper(layoutManager), velocityX, 0); 99c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (vectorForEnd.x < 0) { 100c587f7dba5a337169e854e235da59f595255d6ccAga Madurska hDeltaJump = -hDeltaJump; 101c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 102c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } else { 103c587f7dba5a337169e854e235da59f595255d6ccAga Madurska hDeltaJump = 0; 104c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 105c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (layoutManager.canScrollVertically()) { 106c587f7dba5a337169e854e235da59f595255d6ccAga Madurska vDeltaJump = estimateNextPositionDiffForFling(layoutManager, 107c587f7dba5a337169e854e235da59f595255d6ccAga Madurska getVerticalHelper(layoutManager), 0, velocityY); 108c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (vectorForEnd.y < 0) { 109c587f7dba5a337169e854e235da59f595255d6ccAga Madurska vDeltaJump = -vDeltaJump; 110c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 111c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } else { 112c587f7dba5a337169e854e235da59f595255d6ccAga Madurska vDeltaJump = 0; 113c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 114c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 115c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int deltaJump = layoutManager.canScrollVertically() ? vDeltaJump : hDeltaJump; 116c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (deltaJump == 0) { 117c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return RecyclerView.NO_POSITION; 118c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 119c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 120c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int targetPos = currentPosition + deltaJump; 121c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (targetPos < 0) { 122c587f7dba5a337169e854e235da59f595255d6ccAga Madurska targetPos = 0; 123c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 124c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (targetPos >= itemCount) { 125c587f7dba5a337169e854e235da59f595255d6ccAga Madurska targetPos = itemCount - 1; 126c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 127c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return targetPos; 128c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 129c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 130c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @Override 131c587f7dba5a337169e854e235da59f595255d6ccAga Madurska public View findSnapView(RecyclerView.LayoutManager layoutManager) { 132c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (layoutManager.canScrollVertically()) { 133c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return findCenterView(layoutManager, getVerticalHelper(layoutManager)); 134c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } else if (layoutManager.canScrollHorizontally()) { 135c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return findCenterView(layoutManager, getHorizontalHelper(layoutManager)); 136c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 137c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return null; 138c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 139c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 140c587f7dba5a337169e854e235da59f595255d6ccAga Madurska private int distanceToCenter(@NonNull RecyclerView.LayoutManager layoutManager, 141c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @NonNull View targetView, OrientationHelper helper) { 142c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final int childCenter = helper.getDecoratedStart(targetView) + 143c587f7dba5a337169e854e235da59f595255d6ccAga Madurska (helper.getDecoratedMeasurement(targetView) / 2); 144c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final int containerCenter; 145c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (layoutManager.getClipToPadding()) { 146c587f7dba5a337169e854e235da59f595255d6ccAga Madurska containerCenter = helper.getStartAfterPadding() + helper.getTotalSpace() / 2; 147c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } else { 148c587f7dba5a337169e854e235da59f595255d6ccAga Madurska containerCenter = helper.getEnd() / 2; 149c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 150c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return childCenter - containerCenter; 151c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 152c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 153c587f7dba5a337169e854e235da59f595255d6ccAga Madurska /** 154c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * Estimates a position to which SnapHelper will try to scroll to in response to a fling. 155c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * 156c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * @param layoutManager The {@link RecyclerView.LayoutManager} associated with the attached 157c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * {@link RecyclerView}. 158c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * @param helper The {@link OrientationHelper} that is created from the LayoutManager. 159c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * @param velocityX The velocity on the x axis. 160c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * @param velocityY The velocity on the y axis. 161c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * 162c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * @return The diff between the target scroll position and the current position. 163c587f7dba5a337169e854e235da59f595255d6ccAga Madurska */ 164c587f7dba5a337169e854e235da59f595255d6ccAga Madurska private int estimateNextPositionDiffForFling(RecyclerView.LayoutManager layoutManager, 165c587f7dba5a337169e854e235da59f595255d6ccAga Madurska OrientationHelper helper, int velocityX, int velocityY) { 166c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int[] distances = calculateScrollDistance(velocityX, velocityY); 167c587f7dba5a337169e854e235da59f595255d6ccAga Madurska float distancePerChild = computeDistancePerChild(layoutManager, helper); 168c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (distancePerChild <= 0) { 169c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return 0; 170c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 171c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int distance = 172c587f7dba5a337169e854e235da59f595255d6ccAga Madurska Math.abs(distances[0]) > Math.abs(distances[1]) ? distances[0] : distances[1]; 173f0084673d0d7518e246241ffb99737ddf036e64fAga Madurska if (distance > 0) { 174f0084673d0d7518e246241ffb99737ddf036e64fAga Madurska return (int) Math.floor(distance / distancePerChild); 175f0084673d0d7518e246241ffb99737ddf036e64fAga Madurska } else { 176f0084673d0d7518e246241ffb99737ddf036e64fAga Madurska return (int) Math.ceil(distance / distancePerChild); 177f0084673d0d7518e246241ffb99737ddf036e64fAga Madurska } 178c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 179c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 180c587f7dba5a337169e854e235da59f595255d6ccAga Madurska /** 181c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * Return the child view that is currently closest to the center of this parent. 182c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * 183c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * @param layoutManager The {@link RecyclerView.LayoutManager} associated with the attached 184c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * {@link RecyclerView}. 185c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * @param helper The relevant {@link OrientationHelper} for the attached {@link RecyclerView}. 186c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * 187c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * @return the child view that is currently closest to the center of this parent. 188c587f7dba5a337169e854e235da59f595255d6ccAga Madurska */ 189c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @Nullable 190c587f7dba5a337169e854e235da59f595255d6ccAga Madurska private View findCenterView(RecyclerView.LayoutManager layoutManager, 191c587f7dba5a337169e854e235da59f595255d6ccAga Madurska OrientationHelper helper) { 192c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int childCount = layoutManager.getChildCount(); 193c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (childCount == 0) { 194c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return null; 195c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 196c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 197c587f7dba5a337169e854e235da59f595255d6ccAga Madurska View closestChild = null; 198c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final int center; 199c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (layoutManager.getClipToPadding()) { 200c587f7dba5a337169e854e235da59f595255d6ccAga Madurska center = helper.getStartAfterPadding() + helper.getTotalSpace() / 2; 201c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } else { 202c587f7dba5a337169e854e235da59f595255d6ccAga Madurska center = helper.getEnd() / 2; 203c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 204c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int absClosest = Integer.MAX_VALUE; 205c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 206c587f7dba5a337169e854e235da59f595255d6ccAga Madurska for (int i = 0; i < childCount; i++) { 207c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final View child = layoutManager.getChildAt(i); 208c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int childCenter = helper.getDecoratedStart(child) + 209c587f7dba5a337169e854e235da59f595255d6ccAga Madurska (helper.getDecoratedMeasurement(child) / 2); 210c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int absDistance = Math.abs(childCenter - center); 211c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 212c587f7dba5a337169e854e235da59f595255d6ccAga Madurska /** if child center is closer than previous closest, set it as closest **/ 213c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (absDistance < absClosest) { 214c587f7dba5a337169e854e235da59f595255d6ccAga Madurska absClosest = absDistance; 215c587f7dba5a337169e854e235da59f595255d6ccAga Madurska closestChild = child; 216c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 217c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 218c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return closestChild; 219c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 220c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 221c587f7dba5a337169e854e235da59f595255d6ccAga Madurska /** 222c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * Computes an average pixel value to pass a single child. 223c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * <p> 224c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * Returns a negative value if it cannot be calculated. 225c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * 226c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * @param layoutManager The {@link RecyclerView.LayoutManager} associated with the attached 227c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * {@link RecyclerView}. 228c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * @param helper The relevant {@link OrientationHelper} for the attached 229c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * {@link RecyclerView.LayoutManager}. 230c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * 231c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * @return A float value that is the average number of pixels needed to scroll by one view in 232c587f7dba5a337169e854e235da59f595255d6ccAga Madurska * the relevant direction. 233c587f7dba5a337169e854e235da59f595255d6ccAga Madurska */ 234c587f7dba5a337169e854e235da59f595255d6ccAga Madurska private float computeDistancePerChild(RecyclerView.LayoutManager layoutManager, 235c587f7dba5a337169e854e235da59f595255d6ccAga Madurska OrientationHelper helper) { 236c587f7dba5a337169e854e235da59f595255d6ccAga Madurska View minPosView = null; 237c587f7dba5a337169e854e235da59f595255d6ccAga Madurska View maxPosView = null; 238c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int minPos = Integer.MAX_VALUE; 239c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int maxPos = Integer.MIN_VALUE; 240c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int childCount = layoutManager.getChildCount(); 241c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (childCount == 0) { 242c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return INVALID_DISTANCE; 243c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 244c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 245c587f7dba5a337169e854e235da59f595255d6ccAga Madurska for (int i = 0; i < childCount; i++) { 246c587f7dba5a337169e854e235da59f595255d6ccAga Madurska View child = layoutManager.getChildAt(i); 247c587f7dba5a337169e854e235da59f595255d6ccAga Madurska final int pos = layoutManager.getPosition(child); 248c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (pos == RecyclerView.NO_POSITION) { 249c587f7dba5a337169e854e235da59f595255d6ccAga Madurska continue; 250c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 251c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (pos < minPos) { 252c587f7dba5a337169e854e235da59f595255d6ccAga Madurska minPos = pos; 253c587f7dba5a337169e854e235da59f595255d6ccAga Madurska minPosView = child; 254c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 255c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (pos > maxPos) { 256c587f7dba5a337169e854e235da59f595255d6ccAga Madurska maxPos = pos; 257c587f7dba5a337169e854e235da59f595255d6ccAga Madurska maxPosView = child; 258c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 259c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 260c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (minPosView == null || maxPosView == null) { 261c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return INVALID_DISTANCE; 262c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 263c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int start = Math.min(helper.getDecoratedStart(minPosView), 264c587f7dba5a337169e854e235da59f595255d6ccAga Madurska helper.getDecoratedStart(maxPosView)); 265c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int end = Math.max(helper.getDecoratedEnd(minPosView), 266c587f7dba5a337169e854e235da59f595255d6ccAga Madurska helper.getDecoratedEnd(maxPosView)); 267c587f7dba5a337169e854e235da59f595255d6ccAga Madurska int distance = end - start; 268c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (distance == 0) { 269c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return INVALID_DISTANCE; 270c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 271c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return 1f * distance / ((maxPos - minPos) + 1); 272c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 273c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 274c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @NonNull 275c587f7dba5a337169e854e235da59f595255d6ccAga Madurska private OrientationHelper getVerticalHelper(@NonNull RecyclerView.LayoutManager layoutManager) { 276c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (mVerticalHelper == null || mVerticalHelper.mLayoutManager != layoutManager) { 277c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager); 278c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 279c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return mVerticalHelper; 280c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 281c587f7dba5a337169e854e235da59f595255d6ccAga Madurska 282c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @NonNull 283c587f7dba5a337169e854e235da59f595255d6ccAga Madurska private OrientationHelper getHorizontalHelper( 284c587f7dba5a337169e854e235da59f595255d6ccAga Madurska @NonNull RecyclerView.LayoutManager layoutManager) { 285c587f7dba5a337169e854e235da59f595255d6ccAga Madurska if (mHorizontalHelper == null || mHorizontalHelper.mLayoutManager != layoutManager) { 286c587f7dba5a337169e854e235da59f595255d6ccAga Madurska mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager); 287c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 288c587f7dba5a337169e854e235da59f595255d6ccAga Madurska return mHorizontalHelper; 289c587f7dba5a337169e854e235da59f595255d6ccAga Madurska } 290c587f7dba5a337169e854e235da59f595255d6ccAga Madurska} 291