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