ScrollbarHelper.java revision 392b5deade5236541cd95743001236ac86abd051
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 } 36d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int minPosition = Math.min(lm.getPosition(startChild), lm.getPosition(endChild)); 37d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int maxPosition = Math.max(lm.getPosition(startChild), lm.getPosition(endChild)); 38d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int itemsBefore = reverseLayout 39d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar ? Math.max(0, state.getItemCount() - maxPosition - 1) 40392b5deade5236541cd95743001236ac86abd051Yigit Boyar : Math.max(0, minPosition); 41d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (!smoothScrollbarEnabled) { 42d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return itemsBefore; 43d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 44d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int laidOutArea = Math.abs(orientation.getDecoratedEnd(endChild) - 45d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar orientation.getDecoratedStart(startChild)); 46d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int itemRange = Math.abs(lm.getPosition(startChild) - lm.getPosition(endChild)) + 1; 47d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final float avgSizePerRow = (float) laidOutArea / itemRange; 48d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 49d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return Math.round(itemsBefore * avgSizePerRow + (orientation.getStartAfterPadding() 50d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar - orientation.getDecoratedStart(startChild))); 51d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 52d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 53d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 54d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param startChild View closest to start of the list. (top or left) 55d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param endChild View closest to end of the list (bottom or right) 56d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 57d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar static int computeScrollExtent(RecyclerView.State state, OrientationHelper orientation, 58d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar View startChild, View endChild, RecyclerView.LayoutManager lm, 59d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean smoothScrollbarEnabled) { 60d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null || 61d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar endChild == null) { 62d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return 0; 63d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 64d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (!smoothScrollbarEnabled) { 65d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return Math.abs(lm.getPosition(startChild) - lm.getPosition(endChild)) + 1; 66d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 67d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int extend = orientation.getDecoratedEnd(endChild) 68d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar - orientation.getDecoratedStart(startChild); 69d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return Math.min(orientation.getTotalSpace(), extend); 70d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 71d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar 72d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar /** 73d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param startChild View closest to start of the list. (top or left) 74d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar * @param endChild View closest to end of the list (bottom or right) 75d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar */ 76d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar static int computeScrollRange(RecyclerView.State state, OrientationHelper orientation, 77d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar View startChild, View endChild, RecyclerView.LayoutManager lm, 78d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar boolean smoothScrollbarEnabled) { 79d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null || 80d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar endChild == null) { 81d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return 0; 82d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 83d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar if (!smoothScrollbarEnabled) { 84d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return state.getItemCount(); 85d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 86d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // smooth scrollbar enabled. try to estimate better. 87d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int laidOutArea = orientation.getDecoratedEnd(endChild) - 88d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar orientation.getDecoratedStart(startChild); 89d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar final int laidOutRange = Math.abs(lm.getPosition(startChild) - lm.getPosition(endChild)) 90d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar + 1; 91d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar // estimate a size for full list. 92d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar return (int) ((float) laidOutArea / laidOutRange * state.getItemCount()); 93d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar } 94d7e2f2ab1d253133fa54f309e74a7ee384c33971Yigit Boyar} 95