21

I created the app drawer by using the following library: http://developer.android.com/training/implementing-navigation/nav-drawer.html

I want to show the Navigation Drawer with animation when opening the app. How can I do that?

benleung
  • 871
  • 4
  • 12
  • 25

3 Answers3

53

Predraw listener, aka the safeway

Here is the predraw listener example. It will literally start the animation as soon as it can which maybe a little too fast. You might want to do a combination of this with a runnable shown second. I will not show the two combined, only separate.

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    // Building NavDrawer logic here. Just a method call would be best.
    ...

    ViewTreeObserver vto = drawer.getViewTreeObserver();
    if (vto != null) vto.addOnPreDrawListener(new ShouldShowListener(drawer));
}

private static class ShouldShowListener implements OnPreDrawListener {

    private final DrawerLayout drawerLayout;

    private ShouldShowListener(DrawerLayout drawerLayout) {
        this.drawerLayout= drawerLayout;
    }

    @Override
    public boolean onPreDraw() {
        if (view != null) {
            ViewTreeObserver vto = view.getViewTreeObserver();
            if (vto != null) {
                vto.removeOnPreDrawListener(this);
            }
        }

        drawerLayout.openDrawer(Gravity.LEFT);
        return true;
    }
}

PostDelay Runnable, aka living dangerous

// Delay is in milliseconds
static final int DRAWER_DELAY = 200;

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    // Building NavDrawer logic here. Just a method call would be best.
    ...
    new Handler().postDelayed(openDrawerRunnable(), DRAWER_DELAY);
}

private Runnable openDrawerRunnable() {
    return new Runnable() {

        @Override
        public void run() {
            drawerLayout.openDrawer(Gravity.LEFT);
        }
    }
}

WARNING

If they rotate on the start of the app for the first time BOOM! Read this blog post for more information http://corner.squareup.com/2013/12/android-main-thread-2.html. Best thing to do would be to use the predraw listener or remove your runnable in onPause.

MinceMan
  • 7,483
  • 3
  • 38
  • 40
  • 1
    What if 200ms is not enough in all cases? – Zordid Mar 04 '14 at 14:41
  • Then make it whatever length you need. – MinceMan Mar 05 '14 at 02:50
  • 1
    That's not what I mean. The approach is not good - it fails whenever the preparation takes more time than expected. "Good luck" as you put it really fits... :-) – Zordid Mar 15 '14 at 08:55
  • I hear what you're saying but I would argue that if you're spending more than 200 or 300ms building your drawer and activity after onCreate you're doing something wrong . – MinceMan Mar 15 '14 at 14:00
  • Nope. Nothing wrong. Old device, for example - HTC Hero. Or emulator on my development machine. In such cases, this simply does not work. You need to trigger the opening of the drawer exactly when the Activity is drawn. For that, put an onPreDrawListener to die ViewTreeObserver - that is always better than relying on a fixed timing! – Zordid Mar 16 '14 at 14:36
  • Added predrawlistener as the main asnwer. Thanks for the constructive criticism. – MinceMan Jul 25 '15 at 15:25
  • Can we control the menu items only? – RoCkDevstack May 26 '18 at 03:41
7

You can call openDrawer(int gravity) on the DrawerLayout to make it open the drawer with an animation.

Paul Richter
  • 10,908
  • 10
  • 52
  • 85
Brayden
  • 521
  • 1
  • 5
  • 17
  • I called it in onStart() method of a Fragment Activity, the drawer shows up without animation. Am I calling in the wrong place or what gravity value should I put for the parameter? – benleung Aug 06 '13 at 03:04
  • If it's coming out of the left side of your app, as is typical, use Gravity.LEFT. See if that helps. Otherwise, try calling it later in the fragment life-cycle, such as onResume. – Brayden Aug 06 '13 at 19:02
  • If I call it in onResume(), thats mean the drawer will open even though for multi-task switching? – benleung Aug 08 '13 at 13:41
  • I also am looking for a solution. It does NOT animate when called from onResume() either. There also seems to be a typo in the documentation. On one version of openDrawer it says "...animating it out of view" and on another it says "...animating it into view" – joepetrakovich Aug 09 '13 at 17:39
  • 3
    You can try using the postDelayed(Runnable, long) to delay it by a few moments. That way, it won't be opened until the UI is settled. – ariets Oct 16 '13 at 13:16
  • ...but only if your chosen delay value is enough. Not a nice approach if you ask me, could break if a device is really slow or currently doing a lot of things. – Zordid Mar 04 '14 at 14:26
2

You need to call drawerLayout.openDrawer(Gravity.LEFT) to animate the drawer opening. The drawer won't animate if you make the call too early in the Activity lifecycle.

The simplest solution is to just set a flag in onCreate() and act on it in onResume().

You want to make sure that you only set the flag when savedInstanceState is null indicating that the Activity isn't being resumed from the background. You don't want the drawer sliding out every time you change orientation or switch applications.

public class MainActivity extends ActionBarActivity {
    private DrawerLayout drawerLayout;
    private boolean firstResume = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        drawerLayout = (DrawerLayout)findViewById(R.id.drawer);

        if(savedInstanceState == null){
            firstResume = true;
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        if(firstResume) {
            drawerLayout.openDrawer(Gravity.LEFT);
        }

        firstResume = false;
    }
}

You could also use an OnPreDrawListener but I feel it's a bit unnecessarily complicated as onPreDraw is called multiple times so you need to remove the listener after opening the drawer. You're also assuming that preDraw is a suitable time to activate the drawer which is an internal implementation of the drawer layout. A future implementation might not animate properly until after onDraw for example.

Delaying the drawer opening by an arbitrary number of milliseconds is a dangerous way to solve this problem. In the worst case the call to open the drawer could happen after onDestroy if the user navigates away quickly.

Jared Kells
  • 6,771
  • 4
  • 38
  • 43