Reputation: 39800
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:
onClickListener
to mDrawerLayout
. onClick
never gets calledonTouchListener
to mDrawerLayout
. onTouch
never gets calledActionBarDrawerToggle
and DrawerLayout
classes. Could not find anything like onDrawerStartedOpening
.Upvotes: 65
Views: 51827
Reputation: 20934
DEPRECATED: See other answers for a more suitable solution
There are 2 possible ways to do that:
onDrawerSlide(View drawerView, float slideOffset)
callbackslideOffset
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);
onDrawerStateChanged(int newState)
callbackYou 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);
Upvotes: 87
Reputation: 6373
I don't get why almost everybody here suggested to use settling, while that is called when drawer is settling so no when started opening ? Isn't this question clearly about that ?
How to detect that the DrawerLayout started opening?
Then I don't get how people can propose that code that will be called repeatedly unknown times until opening is finished when using simple callback with slideOffset, this can cause some unknown issues depending on you implementation an it just waste performance. You just want to know when drawer is starting to open and to know it once, not 100 times ...
I don't see as super simple solution but I am implementing it like this:
val DrawerLayout.isDrawerOpen get() = isDrawerOpen(START) || isDrawerOpen(END)
fun DrawerLayout.onDrawerOpening(function: (DrawerLayout) -> Unit) {
val drawerLayout = this
var onDrawerOpeningCalled = false
addDrawerListener(object : SimpleDrawerListener() {
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
super.onDrawerSlide(drawerView, slideOffset)
if (!onDrawerOpeningCalled && slideOffset > 0f && !isDrawerOpen) {
function(drawerLayout)
onDrawerOpeningCalled = true
}
}
override fun onDrawerStateChanged(newState: Int) {
if (newState == STATE_IDLE) onDrawerOpeningCalled = false
}
})
}
Usage:
drawer.onDrawerOpening {
panelView.showingInPager(true) //Just my use case...
}
Upvotes: 1
Reputation: 14618
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()
Upvotes: 10
Reputation: 512
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
}
}
}
});
Upvotes: 11
Reputation: 6153
fookwood answer did not work for me but slight modification in the if statment did the trick)
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, navigationDrawerLayout, topToolbar,
R.string.open_drawer, R.string.close_drawer) {
@Override public void onDrawerStateChanged(int newState) {
if (newState == DrawerLayout.STATE_SETTLING && !navigationDrawerLayout.isDrawerOpen(navigationDrawerView)) {
// this where Drawer start opening
}
Upvotes: 0
Reputation: 64
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close){
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
app.sendScreenView("Menu");
}
};
drawer.setDrawerListener(toggle);
toggle.syncState();
It's the best way.
Upvotes: 1
Reputation: 6736
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!
Upvotes: 47
Reputation: 488
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
}
}
Upvotes: 12