Home | History | Annotate | Download | only in search
      1 package com.android.launcher3.allapps.search;
      2 
      3 import android.content.res.Resources;
      4 import android.graphics.Outline;
      5 import android.support.v7.widget.RecyclerView;
      6 import android.view.View;
      7 import android.view.ViewGroup;
      8 import android.view.ViewOutlineProvider;
      9 
     10 import com.android.launcher3.BaseRecyclerView;
     11 import com.android.launcher3.R;
     12 
     13 /**
     14  * Helper class for controlling the header elevation in response to RecyclerView scroll.
     15  */
     16 public class HeaderElevationController extends RecyclerView.OnScrollListener {
     17 
     18     private final View mHeader;
     19     private final View mHeaderChild;
     20     private final float mMaxElevation;
     21     private final float mScrollToElevation;
     22 
     23     private int mCurrentY = 0;
     24 
     25     public HeaderElevationController(View header) {
     26         mHeader = header;
     27         final Resources res = mHeader.getContext().getResources();
     28         mMaxElevation = res.getDimension(R.dimen.all_apps_header_max_elevation);
     29         mScrollToElevation = res.getDimension(R.dimen.all_apps_header_scroll_to_elevation);
     30 
     31         // We need to provide a custom outline so the shadow only appears on the bottom edge.
     32         // The top, left and right edges are all extended out to match parent's edge, so that
     33         // the shadow is clipped by the parent.
     34         final ViewOutlineProvider vop = new ViewOutlineProvider() {
     35             @Override
     36             public void getOutline(View view, Outline outline) {
     37                 // Set the left and top to be at the parents edge. Since the coordinates are
     38                 // relative to this view,
     39                 //    (x = -view.getLeft()) for this view => (x = 0) for parent
     40                 final int left = -view.getLeft();
     41                 final int top = -view.getTop();
     42 
     43                 // Since the view is centered align, the spacing on left and right are same.
     44                 // Add same spacing on the right to reach parent's edge.
     45                 final int right = view.getWidth() - left;
     46                 final int bottom = view.getHeight();
     47                 final int offset = (int) mMaxElevation;
     48                 outline.setRect(left - offset, top - offset, right + offset, bottom);
     49             }
     50         };
     51         mHeader.setOutlineProvider(vop);
     52         mHeaderChild = ((ViewGroup) mHeader).getChildAt(0);
     53     }
     54 
     55     public void reset() {
     56         mCurrentY = 0;
     57         onScroll(mCurrentY);
     58     }
     59 
     60     @Override
     61     public final void onScrolled(RecyclerView recyclerView, int dx, int dy) {
     62         mCurrentY = ((BaseRecyclerView) recyclerView).getCurrentScrollY();
     63         onScroll(mCurrentY);
     64     }
     65 
     66     private void onScroll(int scrollY) {
     67         float elevationPct = Math.min(scrollY, mScrollToElevation) / mScrollToElevation;
     68         float newElevation = mMaxElevation * elevationPct;
     69         if (Float.compare(mHeader.getElevation(), newElevation) != 0) {
     70             mHeader.setElevation(newElevation);
     71 
     72             // To simulate a scrolling effect for the header, we translate the header down, and
     73             // its content up by the same amount, so that it gets clipped by the parent, making it
     74             // look like the content was scrolled out of the view.
     75             int shift = Math.min(mHeader.getHeight(), scrollY);
     76             mHeader.setTranslationY(-shift);
     77             mHeaderChild.setTranslationY(shift);
     78         }
     79     }
     80 
     81 }
     82