After ViewPropertyAnimator translate animation to View, Empty space is created in relative layout?

796 Views Asked by At

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 :

enter image description here

About the screen layout above :

  1. View 0 has some textual display area.

  2. View 1 which is expected to translate behind View 0 on up-scroll of list view which is inside View 3

  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.

  4. 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 :

enter image description here

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);
        }
}
0

There are 0 best solutions below