I try to make a parallax scrolling effect for google MapView
and RecycleView
using CoordinatorLayour
.
so base on some tutorials found on web I made below code.
The layout:
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.gms.maps.MapView android:id="@+id/map_view"
android:layout_width="match_parent"
android:layout_height="200dp"
app:layout_behavior="net.lunavulpo.coordinatorlayouttest.MapViewBehavior"
/>
<android.support.v7.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_marginTop="200dp"
android:layout_height="match_parent"/>
</android.support.design.widget.CoordinatorLayout>
and I made my implementation of CoordinatorLayout.Behavior
:
public class MapViewBehavior extends CoordinatorLayout.Behavior<MapView> {
public MapViewBehavior(Context context, AttributeSet attrs) {
}
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, MapView child, View dependency) {
return true;
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, MapView child, View directTargetChild, View target, int nestedScrollAxes) {
return true;
}
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, MapView child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
//child.setTranslationY(child.getTranslationY() - dyConsumed);
child.setBottom(child.getBottom() - dyConsumed);
//what should I make here?
}
@Override
public boolean onNestedFling(CoordinatorLayout coordinatorLayout, MapView child, View target, float velocityX, float velocityY, boolean consumed) {
//what should be here?
return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
}
@Override
public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, MapView child, View target, float velocityX, float velocityY) {
//what should be here?
return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
}
}
How to correct implement the parallax scrolling effect?
Maybe there is a library with ready to use Behaviors?
or I miss something and there is a simplest way?
I don't want to use Toolbar for this at all.
Update:
I'm going to give you an overview how to do it (I can't post all the answer because I posted it in another question with MORE requeriments than question and my old answer got marked as duplicated...)any way this is how you do it:
For custom CoordinatorLayout:
Because you can't extend BottomSheetBehavior, you have 2 options: trying doing your own Behavior or like I did, just copy paste the code from original BottomSheetBehavior and modifying it to get another state (when google maps open a bottomsheet it stop in the middle of the screen, this is the state that I'm talking about).
here the CustomBottomSheet with the behavior I was talking above
Now for Image parallax effect:
I tried all default parallax effect in XML avoiding a Custom behavior but in the end I ended doing one, its not hard, you need to override 2 methods like this:
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency instanceof NestedScrollView;
}
public boolean onDependentViewChanged(CoordinatorLayout parent, View child,
View dependency) {
if (mYmultiplier == 0) {
initValues(child, dependency);
return true;
}
float dVerticalScroll = dependency.getY() - mPreviousY;
mPreviousY = dependency.getY();
//going up
if (dVerticalScroll <= 0 && child.getY() <= 0) {
child.setY(0);
return true;
}
//going down
if (dVerticalScroll >= 0 && dependency.getY() <= mImageHeight)
return false;
child.setY( (int)(child.getY() + (dVerticalScroll * mYmultiplier) ) );
return true;
}
Here the link to image parallax behavior
And here is how its looks like:
[]
A link to the project
I must clarify that the previous link has FAB and toolbars animations but if you only want bottom and image behavior just ignore the others java files (clarifying because I have to "adjust to the question")
As @Xaver Kapeller suggested, most painless way to achieve the parallax is to wrap it in CollapsingToolbarLayout
with collapising mode PARALLAX
and parallax multiplier of your choice.
However, if you plan to go with your own behavior, you need to write the implementation in onPreNestedScroll()
method.
First, you only care about vertical scrolling. In onStartNestedScrolling()
you check wither nestedScrollAxes
is vertical.
Then you accumulate all the dy
scrolled and translate the dummy view (that works as header) and MapView
. Reset the mTotalDy
to 0
when there is change in the direction of scrolling.
Then for the same negative mTotalDy
value translate the ViewCompat.setTranslationY(mDummyView, -mTotalDy)
. To achieve proper parallax, the parallax should translate slower than the dummy view, which means that mTotalDy
value should be at least half the speed of translation speed of the dummy view, i.e: ViewCompat.setTranslationY(mMapView, -mTotalDy/2)
. Therefore you will see it translating up/down slower.
View hierarchy should be: Make sure your z-order is preserved as I described
-CordinatorLayout
-FrameLayout
-MapView
-DummyView (same height as MapView, different z-order)
-NestedScrollView (same z-order as DummyView)
You should handle in same manner when there is nested flinging, hint: use target.getScrollY()
, where target is the view that scrolls.