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  */
16 package android.support.v7.widget;
17 
18 import android.view.View;
19 
20 /**
21  * A helper class to do scroll offset calculations.
22  */
23 class 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      */
computeScrollOffset(RecyclerView.State state, OrientationHelper orientation, View startChild, View endChild, RecyclerView.LayoutManager lm, boolean smoothScrollbarEnabled, boolean reverseLayout)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      */
computeScrollExtent(RecyclerView.State state, OrientationHelper orientation, View startChild, View endChild, RecyclerView.LayoutManager lm, boolean smoothScrollbarEnabled)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      */
computeScrollRange(RecyclerView.State state, OrientationHelper orientation, View startChild, View endChild, RecyclerView.LayoutManager lm, boolean smoothScrollbarEnabled)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