How to detect that the DrawerLayout started opening?

50,147

Solution 1

DEPRECATED: See other answers for a more suitable solution

There are 2 possible ways to do that:

  1. Use onDrawerSlide(View drawerView, float slideOffset) callback

slideOffset changes from 0 to 1. 1 means it is completely open, 0 - closed.

Once offset changes from 0 to !0 - it means it started opening process. Something like:

mDrawerToggle = new ActionBarDrawerToggle(
        this,                 
        mDrawerLayout,        
        R.drawable.ic_drawer,  
        R.string.drawer_open,  
        R.string.drawer_close  
) {

    @Override
    public void onDrawerSlide(View drawerView, float slideOffset) {
        if (slideOffset == 0
                && getActionBar().getNavigationMode() == ActionBar.NAVIGATION_MODE_STANDARD) {
            // drawer closed
            getActionBar()
                    .setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
            invalidateOptionsMenu();
        } else if (slideOffset != 0
                && getActionBar().getNavigationMode() == ActionBar.NAVIGATION_MODE_TABS) {
            // started opening
            getActionBar()
                    .setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
            invalidateOptionsMenu();
        }
        super.onDrawerSlide(drawerView, slideOffset);
    }
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
  1. Use onDrawerStateChanged(int newState) callback

You need to listen to STATE_SETTLING states - this state is reported whenever drawer starts moving (either opens or closes). So once you see this state - check whether drawer is opened now and act accordingly:

mDrawerToggle = new ActionBarDrawerToggle(
        this,                 
        mDrawerLayout,        
        R.drawable.ic_drawer,  
        R.string.drawer_open,  
        R.string.drawer_close  
) {
    @Override
    public void onDrawerStateChanged(int newState) {
        if (newState == DrawerLayout.STATE_SETTLING) {
            if (!isDrawerOpen()) {
                // starts opening
                getActionBar()
                        .setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
            } else {
                // closing drawer
                getActionBar()
                        .setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
            }
            invalidateOptionsMenu();
        }
    }
};
mDrawerLayout.setDrawerListener(mDrawerToggle);

Solution 2

Currently accepted answer by Pavel Dudka is already deprecated. Please use mDrawerLayout.addDrawerListener() method instead to set a listener.

mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {

        @Override
        public void onDrawerSlide(View drawerView, float slideOffset) {
            //Called when a drawer's position changes.
        }

        @Override
        public void onDrawerOpened(View drawerView) {
            //Called when a drawer has settled in a completely open state.
            //The drawer is interactive at this point.
            // If you have 2 drawers (left and right) you can distinguish 
            // them by using id of the drawerView. int id = drawerView.getId(); 
            // id will be your layout's id: for example R.id.left_drawer            
        }

        @Override
        public void onDrawerClosed(View drawerView) {
            // Called when a drawer has settled in a completely closed state.
        }

        @Override
        public void onDrawerStateChanged(int newState) {
            // Called when the drawer motion state changes. The new state will be one of STATE_IDLE, STATE_DRAGGING or STATE_SETTLING.
        }
    });

Works perfectly. Cheers!

Solution 3

try to override a method of DrawerLayout.DrawerListener

@Override
public void onDrawerStateChanged(int newState) {
    if( newState == DrawerLayout.STATE_DRAGGING && isDrawerOpen() == false ) {
        // this where Drawer start opening
    }
}

Solution 4

Up-to-date solution:

As others have suggested, the current answer is outdated and it's advised to use mDrawerLayout.addDrawerListener(). A working solution would then be:

mDrawerLayout.addDrawerListener(new DrawerLayout.SimpleDrawerListener() {
        @Override
        public void onDrawerStateChanged(int newState) {
            if (newState == DrawerLayout.STATE_SETTLING && !mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
                // Drawer started opening
            }
        }
    });

Naturally, replace GravityCompat.START with whatever identifies your drawer (layout ID or its gravity ~ location).

Also, if you want to detect when the drawer starts closing, you can simply do:

mDrawerLayout.addDrawerListener(new DrawerLayout.SimpleDrawerListener() {
        @Override
        public void onDrawerStateChanged(int newState) {
            if (newState == DrawerLayout.STATE_SETTLING) {
                if (!mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
                    // Drawer started opening
                } else {
                    // Drawer started closing
                }
            }
        }
    });

Solution 5

For Kotlin

var toggle = object : ActionBarDrawerToggle(this,
                drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) {

            override fun onDrawerOpened(drawerView: View) {
                super.onDrawerOpened(drawerView)
            }
        }
drawer_layout.addDrawerListener(toggle)
toggle.syncState()
Share:
50,147
Oleksiy
Author by

Oleksiy

Updated on July 08, 2022

Comments

  • Oleksiy
    Oleksiy almost 2 years

    So I have tabs that I want to hide when the Navigation Drawer starts opening. The code I have hides them when it finished opening, but it's not what I want.

    mDrawerToggle = new ActionBarDrawerToggle(
            this,                 
            mDrawerLayout,        
            R.drawable.ic_drawer,  
            R.string.drawer_open,  
            R.string.drawer_close  
    ) {
        @Override
        public void onDrawerClosed(View view) {
            invalidateOptionsMenu(); 
            setActionBarMode(ActionBar.NAVIGATION_MODE_TABS);
        }
    
        @Override
        public void onDrawerOpened(View drawerView) {
            invalidateOptionsMenu(); 
            setActionBarMode(ActionBar.NAVIGATION_MODE_STANDARD);
        }
    
    };
    mDrawerLayout.setDrawerListener(mDrawerToggle);
    

    Here's what I tried:

    • Setting an onClickListener to mDrawerLayout. onClick never gets called
    • Setting an onTouchListener to mDrawerLayout. onTouch never gets called
    • Researched ActionBarDrawerToggle and DrawerLayout classes. Could not find anything like onDrawerStartedOpening.
  • Oleksiy
    Oleksiy about 10 years
    The first approach worked for me, however there was one issue. When I tried to slide the drawer not all the way and release it to go to its original position, the tabs didn't restore. It turned out that the call to invalidateOptionsMenu(); has to be before setNavigationMode. Everything else worked fine. Thanks!
  • Parth Sharma
    Parth Sharma almost 9 years
    How i can hide something(Like: FAB button) using onDrawerStateChanged in my MainActivity where i have implement my navigation drawer.. ?
  • Micro
    Micro about 8 years
    Getting a lot deprecated code notifications and "cannot resolve isDrawerOpen()" errors when using onDrawerSlide... Is there an updated answer?
  • Edijae Crusar
    Edijae Crusar almost 8 years
    @ first approach is super awesome
  • Mahendran Sakkarai
    Mahendran Sakkarai about 7 years
    setDrawerListener is deprecated. Changed to addDrawerListener. developer.android.com/reference/android/support/v4/widget/…
  • c0dehunter
    c0dehunter over 6 years
    isDrawerOpen() is not defined. Where is it from?
  • RamithDR
    RamithDR about 6 years
    Most up to date answer! Thanks!
  • Allan Veloso
    Allan Veloso over 5 years
    @PrimožKralj Use DrawerLayout.isDrawerOpen(int drawerGravity)
  • ElliotM
    ElliotM over 5 years
    DrawerLayout.SimpmleDrawerListener is also available and provides no-ops for stuff you don't need.
  • Renetik
    Renetik over 2 years
    This statement is wrong!!! "STATE_SETTLING states - this state is reported whenever drawer starts moving (either opens or closes)" Obviously it is what is written "Indicates that a drawer is in the process of settling to a final position" so you get it late not in the start so unusable for op question. You should remove this from your answer. I just wasted some time because I was testing that because I liked idea at first sight.
  • Pavel Dudka
    Pavel Dudka over 2 years
    @Renetik, well, I would say you should be careful when using a SO answer from 2014 :) I bet APIs have changed since then
  • Renetik
    Renetik over 2 years
    @PavelDudka well sure it changes all the time in some places but here I didn't expect it and answer should be then updated ... I wrote here my answer too after I found issues so maybe this is stack overflow logic that something accepted as answer is true answer forever should be somehow improved.