Search code examples
androidnavigation-drawerandroid-recyclerviewlayout-animation

Drawer item animation when opened


I've created a drawer using a DrawerLayout which contains a RecyclerView with the items. I've also attached a layoutAnimation to the RecyclerView to have the items come in from the side when opening the drawer. This works peachy the first time but when opening the drawer the second time everything is already in place. I would like the layoutAnimation to run every time the drawer is opened.

What I've tried so far is to have a custom ActionBarDrawerToggle (I need that one anyway), and add the following:

@Override
public void onDrawerOpened(final View drawerView) {
    super.onDrawerOpened(drawerView);
    final RecyclerView recyclerView =
            (RecyclerView) drawerView.findViewById(R.id.drawer_content);
    if (recyclerView != null) {
        recyclerView.startLayoutAnimation();
    }
}

It works sort of, because it re-runs the animation, however all the items are there when opening the drawer, then they disappear and then the animations starts.

Anyone have a solution how to "reset" the drawer item views every time the drawer is closed?

Not sure these are needed but I'll include them anyway

<--! layout_animation.xml -->
<layoutAnimation
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/slide_from_right"
    android:delay="15%"
    android:animationOrder="normal"
    />

<--! slide_from_right.xml -->
<translate
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="100%p"
    android:interpolator="@android:anim/decelerate_interpolator"
    android:toXDelta="0"
    />

Solution

  • I found the solution after some more testing, perhaps not the prettiest solution but it works. By hiding the content when the drawer is closed and then making it visible again just before starting the animation solves the issue I was having:

    private boolean mFirstDrawerOpen = true;
    private boolean mAnimationScheduled;
    
    @Override
    public void onDrawerSlide(View drawerView, float slideOffset) {
        super.onDrawerSlide(drawerView, slideOffset);
    
        // The framework handles the first animation
        if (mIsFirstDrawerOpen) {
            mIsFirstDrawerOpen = false;
            return;
        }
    
        final RecyclerView recyclerView =
                (RecyclerView) drawerView.findViewById(R.id.drawer_content);
    
        if (mAnimationScheduled && recyclerView != null) {
            recyclerView.setVisibility(View.VISIBLE);
            recyclerView.startLayoutAnimation();
            mAnimationScheduled = false;
        } else if (slideOffset == 0f) {
            // Handles the case when the drawer is not completly opened and then closed,
            // which does not trigger onDrawerClosed()
            mAnimationScheduled = true;
        }
    }
    
    @Override
    public void onDrawerOpened(final View drawerView) {
        super.onDrawerOpened(drawerView);
    
        mAnimationScheduled = false;
    }
    
    @Override
    public void onDrawerClosed(View drawerView) {
        super.onDrawerClosed(drawerView);
    
        mAnimationScheduled = true;        
    
        final RecyclerView recyclerView =
                (RecyclerView) drawerView.findViewById(R.id.drawer_content);
        if (recyclerView != null) {
            recyclerView.setVisibility(View.INVISIBLE);
        }
    }
    

    Update: The previous answer did not handle the case where the drawer is dragged halfway open and then closed, since onDrawerClosed is not called if the drawer haven't been fully opened. To solve that, I moved most of the code from onDrawerOpen to onDrawerSlide() and modify it a bit.