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