• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 
17 package com.android.launcher3;
18 
19 import android.content.Context;
20 import android.support.v7.widget.RecyclerView;
21 import android.util.AttributeSet;
22 import android.view.MotionEvent;
23 import android.view.View;
24 import android.view.ViewGroup;
25 
26 import com.android.launcher3.views.RecyclerViewFastScroller;
27 
28 
29 /**
30  * A base {@link RecyclerView}, which does the following:
31  * <ul>
32  *   <li> NOT intercept a touch unless the scrolling velocity is below a predefined threshold.
33  *   <li> Enable fast scroller.
34  * </ul>
35  */
36 public abstract class BaseRecyclerView extends RecyclerView  {
37 
38     protected RecyclerViewFastScroller mScrollbar;
39 
BaseRecyclerView(Context context)40     public BaseRecyclerView(Context context) {
41         this(context, null);
42     }
43 
BaseRecyclerView(Context context, AttributeSet attrs)44     public BaseRecyclerView(Context context, AttributeSet attrs) {
45         this(context, attrs, 0);
46     }
47 
BaseRecyclerView(Context context, AttributeSet attrs, int defStyleAttr)48     public BaseRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
49         super(context, attrs, defStyleAttr);
50     }
51 
52     @Override
onAttachedToWindow()53     protected void onAttachedToWindow() {
54         super.onAttachedToWindow();
55         bindFastScrollbar();
56     }
57 
bindFastScrollbar()58     public void bindFastScrollbar() {
59         ViewGroup parent = (ViewGroup) getParent().getParent();
60         mScrollbar = parent.findViewById(R.id.fast_scroller);
61         mScrollbar.setRecyclerView(this, parent.findViewById(R.id.fast_scroller_popup));
62         onUpdateScrollbar(0);
63     }
64 
getScrollbar()65     public RecyclerViewFastScroller getScrollbar() {
66         return mScrollbar;
67     }
68 
getScrollBarTop()69     public int getScrollBarTop() {
70         return getPaddingTop();
71     }
72 
73     /**
74      * Returns the height of the fast scroll bar
75      */
getScrollbarTrackHeight()76     public int getScrollbarTrackHeight() {
77         return mScrollbar.getHeight() - getScrollBarTop() - getPaddingBottom();
78     }
79 
80     /**
81      * Returns the available scroll height:
82      *   AvailableScrollHeight = Total height of the all items - last page height
83      */
getAvailableScrollHeight()84     protected abstract int getAvailableScrollHeight();
85 
86     /**
87      * Returns the available scroll bar height:
88      *   AvailableScrollBarHeight = Total height of the visible view - thumb height
89      */
getAvailableScrollBarHeight()90     protected int getAvailableScrollBarHeight() {
91         int availableScrollBarHeight = getScrollbarTrackHeight() - mScrollbar.getThumbHeight();
92         return availableScrollBarHeight;
93     }
94 
95     /**
96      * Updates the scrollbar thumb offset to match the visible scroll of the recycler view.  It does
97      * this by mapping the available scroll area of the recycler view to the available space for the
98      * scroll bar.
99      *
100      * @param scrollY the current scroll y
101      */
synchronizeScrollBarThumbOffsetToViewScroll(int scrollY, int availableScrollHeight)102     protected void synchronizeScrollBarThumbOffsetToViewScroll(int scrollY,
103             int availableScrollHeight) {
104         // Only show the scrollbar if there is height to be scrolled
105         if (availableScrollHeight <= 0) {
106             mScrollbar.setThumbOffsetY(-1);
107             return;
108         }
109 
110         // Calculate the current scroll position, the scrollY of the recycler view accounts for the
111         // view padding, while the scrollBarY is drawn right up to the background padding (ignoring
112         // padding)
113         int scrollBarY =
114                 (int) (((float) scrollY / availableScrollHeight) * getAvailableScrollBarHeight());
115 
116         // Calculate the position and size of the scroll bar
117         mScrollbar.setThumbOffsetY(scrollBarY);
118     }
119 
120     /**
121      * Returns whether the view itself will handle the touch event or not.
122      * @param ev MotionEvent in {@param eventSource}
123      */
shouldContainerScroll(MotionEvent ev, View eventSource)124     public boolean shouldContainerScroll(MotionEvent ev, View eventSource) {
125         int[] point = new int[2];
126         point[0] = (int) ev.getX();
127         point[1] = (int) ev.getY();
128         Utilities.mapCoordInSelfToDescendant(mScrollbar, eventSource, point);
129         // IF the MotionEvent is inside the thumb, container should not be pulled down.
130         if (mScrollbar.shouldBlockIntercept(point[0], point[1])) {
131             return false;
132         }
133 
134         // IF scroller is at the very top OR there is no scroll bar because there is probably not
135         // enough items to scroll, THEN it's okay for the container to be pulled down.
136         if (getCurrentScrollY() == 0) {
137             return true;
138         }
139         return false;
140     }
141 
142     /**
143      * @return whether fast scrolling is supported in the current state.
144      */
supportsFastScrolling()145     public boolean supportsFastScrolling() {
146         return true;
147     }
148 
149     /**
150      * Maps the touch (from 0..1) to the adapter position that should be visible.
151      * <p>Override in each subclass of this base class.
152      *
153      * @return the scroll top of this recycler view.
154      */
getCurrentScrollY()155     public abstract int getCurrentScrollY();
156 
157     /**
158      * Maps the touch (from 0..1) to the adapter position that should be visible.
159      * <p>Override in each subclass of this base class.
160      */
scrollToPositionAtProgress(float touchFraction)161     public abstract String scrollToPositionAtProgress(float touchFraction);
162 
163     /**
164      * Updates the bounds for the scrollbar.
165      * <p>Override in each subclass of this base class.
166      */
onUpdateScrollbar(int dy)167     public abstract void onUpdateScrollbar(int dy);
168 
169     /**
170      * <p>Override in each subclass of this base class.
171      */
onFastScrollCompleted()172     public void onFastScrollCompleted() {}
173 }