Home | History | Annotate | Download | only in launcher3
      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 
     40     public BaseRecyclerView(Context context) {
     41         this(context, null);
     42     }
     43 
     44     public BaseRecyclerView(Context context, AttributeSet attrs) {
     45         this(context, attrs, 0);
     46     }
     47 
     48     public BaseRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) {
     49         super(context, attrs, defStyleAttr);
     50     }
     51 
     52     @Override
     53     protected void onAttachedToWindow() {
     54         super.onAttachedToWindow();
     55         bindFastScrollbar();
     56     }
     57 
     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 
     65     public RecyclerViewFastScroller getScrollbar() {
     66         return mScrollbar;
     67     }
     68 
     69     public int getScrollBarTop() {
     70         return getPaddingTop();
     71     }
     72 
     73     /**
     74      * Returns the height of the fast scroll bar
     75      */
     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      */
     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      */
     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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    167     public abstract void onUpdateScrollbar(int dy);
    168 
    169     /**
    170      * <p>Override in each subclass of this base class.
    171      */
    172     public void onFastScrollCompleted() {}
    173 }