Search code examples
androidanimationandroid-recyclerviewandroid-coordinatorlayoutandroid-appbarlayout

View animated using CoordinatorLayout and AppBarLayout getting crazy (sometimes)


This thing is getting me nuts.

I have been able to get this behavior (exactly what I want): http://i.imgur.com/PGhL22k.gif

And this is the behavior is has when I scroll down very fast: http://i.imgur.com/kk7icAc.gif and http://i.imgur.com/YNPNiA6.gif

I am sorry but the GIFs are larger than 2Mb and I cannot upload them here...

I want the pagination bar at the bottom to hide the same amount the toolbar does. When scrolling slowly it goes very well, but when fast scrolling it has a really strange behavior as you can see at the GIFs provided above.

This is the layout XML:

<?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:kiosk="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <include
            layout="@layout/android_toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            kiosk:layout_scrollFlags="scroll|enterAlways"/>
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/vpPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        kiosk:layout_behavior="@string/appbar_scrolling_view_behavior"/>

    <include
        layout="@layout/paginator_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        kiosk:layout_behavior="carl.fri.fer.views.KioskPaginator.KioskPaginatorScrollBehaviour"/>
</android.support.design.widget.CoordinatorLayout>

The "android_toolbar" include is as follows:

<?xml version="1.0" encoding="utf-8"?>
<carl.fri.fer.views.KioskToolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/primaryColor"
    android:minHeight="?attr/actionBarSize"/>

And the "paginator_layout" is the following:

<?xml version="1.0" encoding="utf-8"?>
<carl.fri.fer.views.KioskPaginator.KioskPaginator
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/kpPaginator"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:layout_alignParentBottom="true"
    android:animateLayoutChanges="true"
    android:background="@color/primaryColor"
    android:clickable="true"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/tvCurrentPage"
        android:layout_width="50dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:gravity="center"
        android:padding="10dp"
        android:textColor="@color/color_pure_black"
        android:textSize="17sp"/>

    <LinearLayout
        android:id="@+id/llMoreOptions"
        android:layout_width="0dp"
        android:layout_height="40dp"
        android:layout_weight="1"
        android:background="@android:color/transparent"
        android:gravity="center_vertical"
        android:orientation="horizontal"/>

    <TextView
        android:id="@+id/tvTotalPages"
        android:layout_width="50dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:gravity="center"
        android:padding="10dp"
        android:textColor="@color/color_pure_black"
        android:textSize="17sp"/>
</carl.fri.fer.views.KioskPaginator.KioskPaginator>

And the ScrollBehavior is as follows:

public class KioskPaginatorScrollBehaviour extends AppBarLayout.ScrollingViewBehavior {

    public KioskPaginatorScrollBehaviour(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
        return dependency instanceof AppBarLayout;
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
        float depY = - dependency.getHeight();
        depY -= dependency.getY();

        Utils.log("dependency", "" + depY);

        child.setTranslationY(depY);

        return true;
    }
}

Inside of every page of the ViewPager, there is a Fragment. And the content of this Fragment is a RecyclerView with dynamic content. All the content from the RecyclerView is loaded from database and images are loaded at runtime.

Can someone please tell me why is this strange behavior happening? How can I fix it?

Thank you in advance...

EDIT 1:

I just spotted the cause of the weird behavior! The ViewPager loads the current page and the adjoining ones. The content of the RecyclerView loads from the Internet and as soon as it is loaded, it goes into the RecyclerView. The ViewPager first loads the current page and then the adjoining ones. If I have scrolled down the current page RecyclerView (Toolbar is hidden) when the 2nd RecyclerView just loads and shows the content, it resets the current page AppBarLayout behavior, so it resets my custom view behavior... How can I fix that? I want to avoid not loading adjoining views..

EDIT 2:

Ok, it happens when loading adjoining pages of ViewPager and also when loading from the Internet images inside the RecyclerView... this is crazy.


Solution

  • So finally resolved your problem - make your custom behavior extending CoordinatorLayout.Behavior instead of ScrollingViewBehavior and it will work as expected. Just set the value to your view's translationY, that is opposite to Y of AppBarLayout:

    public class KioskPaginatorScrollBehaviour extends CoordinatorLayout.Behavior<View> {
    
        public KioskPaginatorScrollBehaviour(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
            return dependency instanceof AppBarLayout;
        }
    
        @Override
        public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
            float depY = -dependency.getY();
            child.setTranslationY(depY);
            return true;
        }
    }