1d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar/* 2d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Copyright (C) 2014 The Android Open Source Project 3d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * 4d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 5d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * you may not use this file except in compliance with the License. 6d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * You may obtain a copy of the License at 7d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * 8d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 9d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * 10d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * Unless required by applicable law or agreed to in writing, software 11d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 12d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * See the License for the specific language governing permissions and 14d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * limitations under the License. 15d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 16d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyarpackage android.support.v7.widget; 17d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 18d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyarimport android.view.View; 19d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 20d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar/** 21d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * A helper class to do scroll offset calculations. 22d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 23d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyarclass ScrollbarHelper { 24d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 25d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 26d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param startChild View closest to start of the list. (top or left) 27d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param endChild View closest to end of the list (bottom or right) 28d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 29d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar static int computeScrollOffset(RecyclerView.State state, OrientationHelper orientation, 30d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar View startChild, View endChild, RecyclerView.LayoutManager lm, 31d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean smoothScrollbarEnabled, boolean reverseLayout) { 32d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null || 33d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar endChild == null) { 34d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return 0; 35d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 36115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int minPosition = Math.min(lm.getPosition(startChild), 37115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar lm.getPosition(endChild)); 38115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int maxPosition = Math.max(lm.getPosition(startChild), 39115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar lm.getPosition(endChild)); 40d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int itemsBefore = reverseLayout 41d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar ? Math.max(0, state.getItemCount() - maxPosition - 1) 42392b5deade5236541cd95743001236ac86abd051Yigit Boyar : Math.max(0, minPosition); 43d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (!smoothScrollbarEnabled) { 44d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return itemsBefore; 45d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 46d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int laidOutArea = Math.abs(orientation.getDecoratedEnd(endChild) - 47d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar orientation.getDecoratedStart(startChild)); 48115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int itemRange = Math.abs(lm.getPosition(startChild) - 49115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar lm.getPosition(endChild)) + 1; 50d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final float avgSizePerRow = (float) laidOutArea / itemRange; 51d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 52d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return Math.round(itemsBefore * avgSizePerRow + (orientation.getStartAfterPadding() 53d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar - orientation.getDecoratedStart(startChild))); 54d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 55d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 56d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 57d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param startChild View closest to start of the list. (top or left) 58d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param endChild View closest to end of the list (bottom or right) 59d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 60d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar static int computeScrollExtent(RecyclerView.State state, OrientationHelper orientation, 61d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar View startChild, View endChild, RecyclerView.LayoutManager lm, 62d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean smoothScrollbarEnabled) { 63d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null || 64d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar endChild == null) { 65d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return 0; 66d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 67d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (!smoothScrollbarEnabled) { 68d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return Math.abs(lm.getPosition(startChild) - lm.getPosition(endChild)) + 1; 69d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 70d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int extend = orientation.getDecoratedEnd(endChild) 71d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar - orientation.getDecoratedStart(startChild); 72d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return Math.min(orientation.getTotalSpace(), extend); 73d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 74d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 75d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 76d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param startChild View closest to start of the list. (top or left) 77d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param endChild View closest to end of the list (bottom or right) 78d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 79d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar static int computeScrollRange(RecyclerView.State state, OrientationHelper orientation, 80d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar View startChild, View endChild, RecyclerView.LayoutManager lm, 81d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean smoothScrollbarEnabled) { 82d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null || 83d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar endChild == null) { 84d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return 0; 85d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 86d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (!smoothScrollbarEnabled) { 87d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return state.getItemCount(); 88d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 89d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // smooth scrollbar enabled. try to estimate better. 90d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int laidOutArea = orientation.getDecoratedEnd(endChild) - 91d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar orientation.getDecoratedStart(startChild); 92115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar final int laidOutRange = Math.abs(lm.getPosition(startChild) - 93115ba0c7b2a14aa4cd0273952195e1d8f6468f87Yigit Boyar lm.getPosition(endChild)) 94d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar + 1; 95d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // estimate a size for full list. 96d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return (int) ((float) laidOutArea / laidOutRange * state.getItemCount()); 97d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 98d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar} 99