1package com.android.launcher3.allapps; 2 3import android.annotation.TargetApi; 4import android.content.res.Resources; 5import android.graphics.Outline; 6import android.graphics.Rect; 7import android.graphics.drawable.GradientDrawable; 8import android.os.Build; 9import android.support.v7.widget.RecyclerView; 10import android.view.View; 11import android.view.ViewGroup; 12import android.view.ViewOutlineProvider; 13import android.widget.FrameLayout; 14 15import com.android.launcher3.BaseRecyclerView; 16import com.android.launcher3.R; 17 18/** 19 * Helper class for controlling the header elevation in response to RecyclerView scroll. 20 */ 21public abstract class HeaderElevationController extends RecyclerView.OnScrollListener { 22 23 private int mCurrentY = 0; 24 25 public void reset() { 26 mCurrentY = 0; 27 onScroll(mCurrentY); 28 } 29 30 @Override 31 public final void onScrolled(RecyclerView recyclerView, int dx, int dy) { 32 mCurrentY = ((BaseRecyclerView) recyclerView).getCurrentScrollY(); 33 onScroll(mCurrentY); 34 } 35 36 public void updateBackgroundPadding(Rect bgPadding) { } 37 38 abstract void onScroll(int scrollY); 39 40 public static class ControllerV16 extends HeaderElevationController { 41 42 private final View mShadow; 43 private final float mScrollToElevation; 44 45 public ControllerV16(View header) { 46 Resources res = header.getContext().getResources(); 47 mScrollToElevation = res.getDimension(R.dimen.all_apps_header_scroll_to_elevation); 48 49 mShadow = new View(header.getContext()); 50 mShadow.setBackground(new GradientDrawable( 51 GradientDrawable.Orientation.TOP_BOTTOM, new int[] {0x1E000000, 0x00000000})); 52 mShadow.setAlpha(0); 53 54 FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( 55 FrameLayout.LayoutParams.MATCH_PARENT, 56 res.getDimensionPixelSize(R.dimen.all_apps_header_shadow_height)); 57 lp.topMargin = ((FrameLayout.LayoutParams) header.getLayoutParams()).height; 58 59 ((ViewGroup) header.getParent()).addView(mShadow, lp); 60 } 61 62 @Override 63 public void onScroll(int scrollY) { 64 float elevationPct = (float) Math.min(scrollY, mScrollToElevation) / 65 mScrollToElevation; 66 mShadow.setAlpha(elevationPct); 67 } 68 69 @Override 70 public void updateBackgroundPadding(Rect bgPadding) { 71 FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mShadow.getLayoutParams(); 72 lp.leftMargin = bgPadding.left; 73 lp.rightMargin = bgPadding.right; 74 mShadow.requestLayout(); 75 } 76 } 77 78 @TargetApi(Build.VERSION_CODES.LOLLIPOP) 79 public static class ControllerVL extends HeaderElevationController { 80 81 private final View mHeader; 82 private final float mMaxElevation; 83 private final float mScrollToElevation; 84 85 public ControllerVL(View header) { 86 mHeader = header; 87 Resources res = mHeader.getContext().getResources(); 88 mMaxElevation = res.getDimension(R.dimen.all_apps_header_max_elevation); 89 mScrollToElevation = res.getDimension(R.dimen.all_apps_header_scroll_to_elevation); 90 91 // We need to provide a custom outline so the shadow only appears on the bottom edge. 92 // The top, left and right edges are all extended out, and the shadow is clipped 93 // by the parent. 94 final ViewOutlineProvider vop = new ViewOutlineProvider() { 95 @Override 96 public void getOutline(View view, Outline outline) { 97 final View parent = (View) mHeader.getParent(); 98 99 final int left = parent.getLeft(); // Use the parent to account for offsets 100 final int top = view.getTop(); 101 final int right = left + view.getWidth(); 102 final int bottom = view.getBottom(); 103 104 outline.setRect( 105 left - (int) mMaxElevation, 106 top - (int) mMaxElevation, 107 right + (int) mMaxElevation, 108 bottom); 109 } 110 }; 111 mHeader.setOutlineProvider(vop); 112 } 113 114 @Override 115 public void onScroll(int scrollY) { 116 float elevationPct = Math.min(scrollY, mScrollToElevation) / mScrollToElevation; 117 float newElevation = mMaxElevation * elevationPct; 118 if (Float.compare(mHeader.getElevation(), newElevation) != 0) { 119 mHeader.setElevation(newElevation); 120 } 121 } 122 } 123} 124