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