Created
November 4, 2017 15:06
-
-
Save sunwicked/1beaee6bac3bb8f237470848ba200243 to your computer and use it in GitHub Desktop.
Custom LinearLayoutManager for scaling, fading and snapping children to top
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class CustomLayoutManager extends LinearLayoutManager { | |
private final float mShrinkAmount = 0.15f; | |
private final float mShrinkDistance = 0.9f; | |
Context mContext; | |
//Make an instance variable at the top of you LayoutManager | |
private static final float MILLISECONDS_PER_INCH = 50f; | |
public CustomLayoutManager(Context context) { | |
super(context); | |
mContext = context; | |
} | |
public CustomLayoutManager(Context context, int orientation, boolean reverseLayout) { | |
super(context, orientation, reverseLayout); | |
this.mContext = context; | |
} | |
@Override | |
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { | |
int orientation = getOrientation(); | |
if (orientation == VERTICAL) { | |
int scrolled = super.scrollVerticallyBy(dy, recycler, state); | |
float midpoint = getHeight() / 2.f; | |
float d0 = 0.f; | |
float d1 = mShrinkDistance * midpoint; | |
float s0 = 1.f; | |
float s1 = 1.f - mShrinkAmount; | |
for (int i = 0; i < getChildCount(); i++) { | |
child = getChildAt(i); | |
float childMidpoint = | |
(getDecoratedBottom(child) + getDecoratedTop(child)) / 2.f; | |
float d = Math.min(d1, Math.abs(midpoint - childMidpoint)); | |
float scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0); | |
child.setScaleX(scale); | |
child.setScaleY(scale); | |
if (scale > .9f) { | |
child.setAlpha(1f); | |
} else { | |
child.setAlpha(0.5f); | |
} | |
} | |
scrolled; | |
} else { | |
return 0; | |
} | |
} | |
@Override | |
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { | |
int orientation = getOrientation(); | |
if (orientation == HORIZONTAL) { | |
int scrolled = super.scrollHorizontallyBy(dx, recycler, state); | |
float midpoint = getWidth() / 2.f; | |
float d0 = 0.f; | |
float d1 = mShrinkDistance * midpoint; | |
float s0 = 1.f; | |
float s1 = 1.f - mShrinkAmount; | |
for (int i = 0; i < getChildCount(); i++) { | |
View child = getChildAt(i); | |
float childMidpoint = | |
(getDecoratedRight(child) + getDecoratedLeft(child)) / 2.f; | |
float d = Math.min(d1, Math.abs(midpoint - childMidpoint)); | |
float scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0); | |
child.setScaleX(scale); | |
child.setScaleY(scale); | |
if (scale > .9f) { | |
child.setAlpha(1f); | |
} else { | |
child.setAlpha(0.5f); | |
} | |
} | |
return scrolled; | |
} else { | |
return 0; | |
} | |
} | |
@Override | |
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { | |
//Create RecyclerView.SmoothScroller instance? Check. | |
LinearSmoothScroller smoothScroller = | |
new LinearSmoothScroller(mContext) { | |
//Automatically implements method on instantiation. | |
//This controls the direction in smoothScroll looks for your | |
//list item | |
@Override | |
public PointF computeScrollVectorForPosition | |
(int targetPosition) { | |
//What is PointF? A class holds two float coordinates. | |
//Accepts a (x , y) | |
//for y: use -1 for up direction, 1 for down direction. | |
//for x (did not test): use -1 for direction, 1 for right | |
//direction. | |
//We let our custom LinearLayoutManager calculate PointF for us | |
return CustomLayoutManager.this.computeScrollVectorForPosition | |
(targetPosition); | |
} | |
//The holy grail of smooth scrolling | |
//returns the milliseconds it takes to scroll one pixel. | |
@Override | |
protected float calculateSpeedPerPixel | |
(DisplayMetrics displayMetrics) { | |
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi; | |
} | |
@Override | |
protected int getVerticalSnapPreference() { | |
return LinearSmoothScroller.SNAP_TO_START; | |
} | |
}; | |
//Docs do not tell us anything this, | |
//but we need to set the position we to scroll to. | |
smoothScroller.setTargetPosition(position); | |
startSmoothScroll(smoothScroller); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment