Animate drawer icon into arrow on setDisplayHomeAsUpEnabled?

22,997

Solution 1

I haven't tested this, but you may be able to achieve this by animating a float between 0 (drawer closed) and 1 (drawer open) and then passing the value into ActionBarDrawerToggle.onDrawerSlide(View, float). I believe that's how the toggle determines what state the animated toggle should be in.

Something like this should work.

ValueAnimator anim = ValueAnimator.ofFloat(start, end);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator valueAnimator) {
        float slideOffset = (Float) valueAnimator.getAnimatedValue();
        toolbarDrawerToggle.onDrawerSlide(drawerLayout, slideOffset);
    }
});
anim.setInterpolator(new DecelerateInterpolator());
// You can change this duration to more closely match that of the default animation.
anim.setDuration(500);
anim.start();

Solution 2

Since the question was asked, an alternative way has become available. The animated arrow is implemented by the now public class DrawerArrowDrawable which implements Drawable.

In your code, set the navigation icon as follows:

DrawerArrowDrawable drawerArrow = new DrawerArrowDrawable(this);
drawerArrow.setColor(myColor);

toolbar.setNavigationIcon(drawerArrow);

Register an OnBackStackChangedListener and animate the arrow manually:

@Override
public void onBackStackChanged() {
    boolean drawer = getSupportFragmentManager().getBackStackEntryCount() == 0;
    ObjectAnimator.ofFloat(drawerArrow, "progress", drawer ? 0 : 1).start();
}
Share:
22,997
Vextil
Author by

Vextil

Updated on August 17, 2020

Comments

  • Vextil
    Vextil almost 4 years

    I'm using setDisplayHomeAsUpEnabled in order to show the arrow instead of the drawer "burger" icon but it's not getting animated or anything. Instead it shows the arrow drawable instantaneously.

    Home screen: (Album 1)

    When you tap a movie: (Album 2)

    The thing is, the icon does the animation just fine when I slide the drawer, which makes me think that maybe I'm not supposed to use setDisplayHomeAsUpEnabled for this: (Album 3)

    Album: http://imgur.com/a/LkXbh

    Here's my drawer toggle code:

        Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
        setSupportActionBar(toolbar);
    
        drawerAdapter = new DrawerAdapter(this, App.getNavItems(), getSupportFragmentManager());
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawerList = (ExpandableListView) findViewById(R.id.left_drawer);
    
        // Set onGroupClick and onChildClick
        drawerAdapter.setClickEvents(MainActivity.this, drawerLayout, drawerList);
        drawerList.setAdapter(drawerAdapter);
    
        ActionBarDrawerToggle toolbarDrawerToggle = new ActionBarDrawerToggle(
                this,                 
                drawerLayout,        
                toolbar,             
                R.string.drawer_open, 
                R.string.drawer_close 
        ) {
    
            public void onDrawerClosed(View view) {
                super.onDrawerClosed(view);
                invalidateOptionsMenu();
            }
    
            public void onDrawerOpened(View view) {
                super.onDrawerOpened(view);
                invalidateOptionsMenu();
            }
        };
        drawerLayout.setDrawerListener(toolbarDrawerToggle);
        toolbarDrawerToggle.syncState();
    

    EDIT: I want the animation not when opening the drawer, that works already. I would like to manually trigger the animation when I load a specific fragment. I may not have explained myself correctly.

  • Vextil
    Vextil over 9 years
    I have the material theme and the ActionBarDrawerToggle is the one from v7. Is there a way to change the icon to an arrow animating it programatically then? I want the animation not when opening the drawer, that works already. I would like to manually trigger the animation when I load a specific fragment. I may not have explained myself correctly.
  • Philio
    Philio over 9 years
    In that case you could use setDisplayHomeAsUpEnabled(true) and you would get a back arrow rather than a hamburger, but if you still have the nav drawer active then I don't think that's really as it's intended to work. If you check the Google apps that have been updated to the material theme you won't find any screens with a back arrow and an active nav drawer.
  • Philio
    Philio over 9 years
    From a UX perspective, user expects: There is a hamburger = there is a nav drawer. There is a back arrow = go back to the previous screen.
  • Vextil
    Vextil over 9 years
    That's true, and I understand that the user does not expect a drawer when there's an arrow. The thing is, my idea was to lock the drawer and show a back arrow because I wanted to avoid creating a new activity which allows me to transition the movie poster from the previous fragment into the new one with the new animation APIs and change the Toolbar background color smoothly.
  • Philio
    Philio over 9 years
    Sounds like that should work. Add new fragment, add to back stack, show back arrow, lock the drawer. Then when back is pressed change back to a hamburger and enable the drawer again.
  • Vextil
    Vextil over 9 years
    There's still no way to animate the hamburger into an arrow right?
  • Nathan Walters
    Nathan Walters over 9 years
    @Philio "If you check the Google apps that have been updated to the material theme you won't find any screens with a back arrow and an active nav drawer." That's blatantly false. Click on an app in the Play Store to open its details activity: the back arrow is displayed, but you can still swipe in the nav drawer. Joaquin is asking how to trigger the hamburger->arrow animation manually.
  • Philio
    Philio over 9 years
    Ah I see what you mean, I don't know of a way to animate the hamburger into a back arrow.
  • Nathan Walters
    Nathan Walters over 9 years
    @Philio it works for me on both Play Games, Play Store, and Play Music. What version of Android are you running?
  • Philio
    Philio over 9 years
    I restarted the phone and actually the nav drawer is working now as you suggested in all the Google apps. Strange! In fact in Play Music, it's messed up and when you're in a details activity you still get close animations and the hamburger jumps back to an arrow :)
  • Vextil
    Vextil over 9 years
    I cant, I need 15 reputation sorry :(
  • Raveesh Bhalla
    Raveesh Bhalla over 9 years
    This works perfectly. Just set start=0 and end=1 to go from hamburger to arrow, and start=1 and end=0 for arrow to hamburger. One thing you'll have to keep track of is when the drawer is closed when the arrow is shown. At this point, the hamburger ends up being shown (because of the drawer's slide), which you'll have to correct.
  • russellhoff
    russellhoff over 9 years
    This works prefectly when you click on the icon to open it and to close it. It also works when you slide the drawer either to open it or to close it. But, what I miss is the effect shown when you slide the drawer, i.e. the transition. How can I reproduce it? Here you can see the transition between hamburger to arrow youtube.com/watch?v=D8U-FKSrGVs, and here after implementing your solution youtube.com/watch?v=abvi8gHzHkU
  • Nathan Walters
    Nathan Walters over 9 years
    @russellhoff if you post that as a new question with some of your code, I may be able to help you.
  • russellhoff
    russellhoff over 9 years
    @NathanWalters here it's the question stackoverflow.com/questions/27187312/…. Thanks!
  • Sotti
    Sotti over 9 years
    This was it to me. Thanks
  • Tejas Sherdiwala
    Tejas Sherdiwala about 9 years
    Works like a charm. Thank you.
  • Eurig Jones
    Eurig Jones almost 9 years
    @NathanWalters This works when going from back button to hamburger whilst using setDisplayHomeAsUpEnabled(false), but it doesn't work the other way around even if I swap 0, 1 start, end. Any idea how this could be done?
  • Javier Delgado
    Javier Delgado over 8 years
    Which is the class that has the onBackStackChanged() method?
  • Kirill Rakhman
    Kirill Rakhman over 8 years
  • jlively
    jlively over 6 years
    What's drawer in this case?
  • Kirill Rakhman
    Kirill Rakhman over 6 years
    @jlively all the required code is included. boolean drawer indicates whether the drawable should display the hamburger or the back arrow.