Skip to content

Instantly share code, notes, and snippets.

@BenDLH
Last active February 21, 2017 13:05
Show Gist options
  • Save BenDLH/7aeb30d475a4ab309c99b3afa871b63f to your computer and use it in GitHub Desktop.
Save BenDLH/7aeb30d475a4ab309c99b3afa871b63f to your computer and use it in GitHub Desktop.
CoordinatorLayout behaviour for a parallaxing header above a RecyclerView
//
// 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