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