Last active
February 21, 2017 13:05
-
-
Save BenDLH/7aeb30d475a4ab309c99b3afa871b63f to your computer and use it in GitHub Desktop.
CoordinatorLayout behaviour for a parallaxing header above a RecyclerView
This file contains 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
// | |
// ParallaxScrollBehaviour | |
// Created by Ben De La Haye on 17/10/2016 | |
// | |
public class ParallaxScrollBehavior<V extends View> extends CoordinatorLayout.Behavior<V> { | |
private static final float PARALLAX_RATIO = 0.8f; | |
private RecyclerView _recyclerView; | |
private V _child; | |
private RecyclerView.OnScrollListener _scrollListener = new RecyclerView.OnScrollListener() { | |
@Override | |
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {} | |
@Override | |
public void onScrolled(RecyclerView recyclerView, int dx, int dy) { | |
// We can only trust the position of the top view for an accurate scroll position | |
if (_recyclerView.getLayoutManager() != null && _recyclerView.getLayoutManager().getChildAt(0) != null) { | |
int decoratedTop = _recyclerView.getLayoutManager().getDecoratedTop(_recyclerView.getLayoutManager().getChildAt(0)); | |
_child.setTranslationY((decoratedTop - _child.getHeight()) * PARALLAX_RATIO); | |
} | |
} | |
}; | |
public ParallaxScrollBehavior() {} | |
public ParallaxScrollBehavior(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
} | |
@Override | |
public boolean layoutDependsOn(CoordinatorLayout parent, V child, View dependency) { | |
// This is the (header) View this behaviour is attached to | |
_child = child; | |
// We want to get a reference to the first RecyclerView child of the coordinator layout | |
if (dependency instanceof RecyclerView) { | |
_recyclerView = ((RecyclerView) dependency); | |
// This method may be called multiple times, and we only want one _listener | |
_recyclerView.removeOnScrollListener(_scrollListener); | |
// Add a _listener so we can get updates for scroll events | |
_recyclerView.addOnScrollListener(_scrollListener); | |
return true; | |
} | |
// We don't care about getting updates to onDependantViewChanged() | |
return false; | |
} | |
@Override | |
public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) { | |
// We can only trust the position of the top view for an accurate scroll position | |
if (_recyclerView != null && _recyclerView.getLayoutManager() != null && _recyclerView.getLayoutManager().getChildAt(0) != null) { | |
int decoratedTop = _recyclerView.getLayoutManager().getDecoratedTop(_recyclerView.getLayoutManager().getChildAt(0)); | |
_child.setTranslationY((decoratedTop - _child.getHeight()) * PARALLAX_RATIO); | |
} | |
return super.onLayoutChild(parent, child, layoutDirection); | |
} | |
@Override | |
public boolean onDependentViewChanged(CoordinatorLayout parent, V child, View dependency) { | |
_child.post(() -> { | |
if (_recyclerView.getPaddingTop() < _child.getHeight()) { | |
// Add enough padding to the RecyclerView to show our header above it | |
_recyclerView.setPadding(_recyclerView.getPaddingLeft(), _child.getHeight(), _recyclerView.getPaddingRight(), _recyclerView.getPaddingBottom()); | |
} | |
}); | |
return true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment