I wanted an animated effect just like in YouTube or Gmail application. Where the top bar translates out side the upper line of screen when scrolling down & vice versa. But my case is little different, my screen layout as follows :
About the screen layout above :
View 0 has some textual display area.
View 1 which is expected to translate behind View 0 on up-scroll of list view which is inside View 3
View 2 will also translate above & just below the View 0 on same list view up-scroll event in View 3 but it will stay visible on screen just below View 0 at this point View 1 will be completely hidden behind the View 0.
View 3 is list view containing area and is expected to be below View 2 even after up translation of View 2.
Fortunately I cam across this article which does the exact same thing I want to achieve, with little size tweaks as per my requirements I am able to translate View 1 behind View 0 & View 2 Just below View 0. The translation is given to the parent which holds both View 1 & 2 but with only height of View 1, cause of this View 2 stays visible below View 0.
Now the problem I am facing here is On translation there is new empty area getting created at the original positions of View 1 & View 2. As shown in below screen :
Actually all View 0 up-to 3 are relative layouts & they are defined in a parent who is also relative layout. View 3 has property below View 2. But after translate animation View 3 stays at the position where it was in the beginning only View 2 moves upwards.
I tried putting View 3 as part of translation animation, in that case it moves along with View 2 upwards, but at the bottom of it ( View 3) leaves behind blank space. Why this may happen ? What should I do to keep View 3 below View 2 even after animations ?
Here is article which I have followed : https://rylexr.tinbytes.com/2015/04/27/how-to-hideshow-android-toolbar-when-scrolling-google-play-musics-behavior/
Android blog for ViewPropertyAnimator : https://android-developers.googleblog.com/2011/05/introducing-viewpropertyanimator.html
I searched lot for this solution I tried different things but nothing worked finally I thought I should post question so that if anyone who has already faced this kind of issue may have something helpful.
Thanks for reading this huge question.
Here is code :
XML
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/top_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--
Some text views for information
-->
<RelativeLayout
android:id="@+id/container_veiw"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!-- Below view holds view 2 at the bottom -->
<RelativeLayout
android:id="@+id/animate_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:fillAfter="true"
android:fillEnabled="true">
<!-- Below relative layout is xepected to be hidden behind top area -->
<!-- Below is view 1 in diagram -->
<RelativeLayout
android:id="@+id/animate_child"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="@color/black_background">
<LinearLayout
android:id="@+id/some_other_views"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_alignParentTop="true"
android:layout_margin="16dp"
android:animateLayoutChanges="true"
android:orientation="horizontal">
<!-- Some child views -->
</LinearLayout>
</RelativeLayout>
<!-- This is view 2 -->
<RelativeLayout
android:id="@+id/view2"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_below="@id/animate_child"
android:background="@android:color/white">
<!-- Some child views -->
</RelativeLayout>
</RelativeLayout>
<!-- At this place after animation empty area is getting created -->
<!-- Below relative layout is expected to be just below @id/animate_parent -->
<!-- This is view 3 -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_below="@id/animate_parent"
android:background="#ffffff">
<android.support.v7.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:background="#ffffff"
android:fadeScrollbars="false"
android:scrollbarAlwaysDrawVerticalTrack="true"
tools:listitem="@layout/fragment_document" />
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
Java Code :
Scroll listener on recycler view :
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (scrollingUp) {
if (verticalOffset > animate_child.getHeight()) {
animateHide();
} else {
animateShow(verticalOffset);
}
} else {
if (animate_child.getTranslationY() < animate_child.getHeight() * -0.6 && verticalOffset > animate_child.getHeight()) {
animateHide();
} else {
animateShow(verticalOffset);
}
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
verticalOffset += dy;
scrollingUp = dy > 0;
int toolbarYOffset = (int) (dy - animate_parent.getTranslationY());
animate_parent.animate().cancel();
if (scrollingUp) {
if (toolbarYOffset < animate_child.getHeight()) {
if (verticalOffset > animate_child.getHeight()) {
toolbarSetElevation(ELEVATION_CONSTANT);
}
animate_parent.setTranslationY(-toolbarYOffset);
} else {
toolbarSetElevation(0);
animate_parent.setTranslationY(-animate_child.getHeight());
}
} else {
if (toolbarYOffset < 0) {
if (verticalOffset <= 0) {
toolbarSetElevation(0);
}
animate_parent.setTranslationY(0);
} else {
if (verticalOffset > animate_child.getHeight()) {
toolbarSetElevation(ELEVATION_CONSTANT);
}
animate_parent.setTranslationY(-toolbarYOffset);
}
}
}
});
Helper functions :
private void animateShow(final int verticalOffset) {
animate_parent.animate()
.translationY(0)
.setInterpolator(new LinearInterpolator())
.setDuration(180)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
setElevation(verticalOffset == 0 ? 0 : ELEVATION_CONSTANT);
}
});
}
private void animateHide() {
animate_parent.animate()
.translationY(-animate_child.getHeight())
.setInterpolator(new LinearInterpolator())
.setDuration(180)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
setElevation(0);
}
});
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void setElevation(float elevation) {
// setElevation() only works on Lollipop
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
animate_parent.setElevation(elevation);
}
}