Skip to content

Instantly share code, notes, and snippets.

@sunwicked
Created November 4, 2017 15:06
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sunwicked/1beaee6bac3bb8f237470848ba200243 to your computer and use it in GitHub Desktop.
Save sunwicked/1beaee6bac3bb8f237470848ba200243 to your computer and use it in GitHub Desktop.
Custom LinearLayoutManager for scaling, fading and snapping children to top
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