23

I have a main activity that is situated with two navigation drawers. The left one is always accessible, but the right one is used for displaying some necessary lists and performing certain actions. When I have certain fragments loaded into the center FrameLayout of the activity they have actions that require the right drawer be opened and an item be selected. All of this is working great, but I want to make sure that when either the back button is pressed or the screen is clicked outside the drawer that the drawer is closed, locked and the fragment loaded in there is removed. I should also mention that this right drawer holds a FrameLayout and relies on fragments.

In my main activity this is what I'm calling:

@Override       
public void onBackPressed(){
    Log.d(TAG, "onBackPressed() called");
    if(drawerLayoutRight.isDrawerOpen(drawerFrameRight)){
        Log.d(TAG, "----------------------");
        drawerLayoutRight.closeDrawer(drawerFrameRight);
        drawerLayoutRight.setDrawerLockMode(1, drawerFrameRight);
        ExcerciseList fragment = (ExcerciseList) getFragmentManager().findFragmentById(R.id.right_drawer);
        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        transaction.remove(fragment).commit();
    } else {        
        super.onBackPressed();
    }
}

I also tried:

public boolean onKeyDown(int keyCode, KeyEvent event){
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        Log.d(TAG, "onKeyDown called");
        return true;
    }

    return super.onKeyDown(keyCode, event);
}

But this hasn't worked either. Whenever I click the back button the drawer will close, but neither of these methods would be called. But once the drawer is closed, if the back button is pressed these methods will be invoked. I was also wondering if anyone knew of a simple way to handle a click outside of the drawer. I figure I could make a custom DrawerLayout and override drawerClose() or check the coordinates that are clicked on a touch event. Just curious if anyone has a simpler way.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Ryan Smith
  • 1,628
  • 3
  • 13
  • 18
  • The `DrawerLayout` (I assume that's what you're using) will consume the back button event if the drawer is opened. Check out the `onKeyDown()` and `onKeyUp()` methods (in the source code). – MH. Aug 17 '13 at 22:16
  • So for the `onKeyDown()` listener where would I use this. It seems cyclical to me because wouldn't I have to know when the beck button is pressed, which isn't working? Can you clear this up for me? – Ryan Smith Aug 17 '13 at 22:28
  • I think that I may be able to use a `DrawerListener` to deal with this. Because the drawer is closing everytime the back button is pressed. – Ryan Smith Aug 17 '13 at 22:31
  • Check this [answer](http://stackoverflow.com/a/32249563/1118886) out. it might solve your problem – Sheraz Ahmad Khilji Aug 27 '15 at 12:38

8 Answers8

73

Put this line into your code:

mDrawerLayout.setFocusableInTouchMode(false);

Then it will call your overwritten onBackPressed() when you press the back button.

Neoh
  • 15,906
  • 14
  • 66
  • 78
2

Quoting myself from the question at Force EditText to lose focus when back pressed

"In my experience onBackPressed() (at least the default @Override one in an activity) will not normally fire when pushing the back button to close the keyboard. As far as I know it will only fire when a Back press would initiate a finish() on the current activity."

This probably applies the same way to the navigation drawer.

This is most likely due to the fact that the current "Activity" is not in focus when the drawer opens (same with the SoftKeyboard) so the @Override back button is not called.

Community
  • 1
  • 1
Shadesblade
  • 782
  • 5
  • 5
1

I was able to solve my problem by using DrawerLayout.DrawerListener. This worked in my situation because when the back button was being pressed the drawer was still closing even though the method onBackPressed() wasn't being called.

@MH said, "The DrawerLayout (I assume that's what you're using) will consume the back button event if the drawer is opened."

Although in the documentation I could not find an explicit mention of this; there was some mention of the back button here. Unfortunately it was not of much help.

What @MH said explains why onBackPressed() was not being called when the drawer was opened, and why it was being called while it was closed.

drawerLayoutRight.setDrawerListener(this);

Where drawerLayoutRight is a DrawerLayout. And my listener looks like this:

@Override
public void onDrawerClosed(View arg0) {
    if(drawerLayoutRight.getDrawerLockMode(drawerFrameRight)!= 1){
        drawerLayoutRight.setDrawerLockMode(1, drawerFrameRight);
    }
    ExcerciseList fragment = (ExcerciseList) getFragmentManager().findFragmentById(R.id.right_drawer);
    if (fragment != null) {
        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        transaction.remove(fragment).commit();
    }
}

onDrawerOpened(), onDrawerSlide() and onDrawerStateChanged() are all empty. Only one of my drawers is using the listener so I don't have to check the view.

Ryan Smith
  • 1,628
  • 3
  • 13
  • 18
1

Just simple overrede your activity or drawerlayout, will do.

@Override public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (KeyEvent.KEYCODE_BACK == keyCode
            && mDrawerLayout != null
            && mDrawerLayout.isDrawerOpen(leftDrawerView)) {
        KeyEventCompat.startTracking(event);
        return true;
    }
    return super.onKeyDown(keyCode, event);
}

@Override public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (KeyEvent.KEYCODE_BACK == keyCode
            && !event.isCanceled()
            && mDrawerToggle != null
            && mDrawerLayout.isDrawerOpen(leftDrawerView)) {
        mDrawerLayout.closeDrawers();
        return true;
    }
    return super.onKeyUp(keyCode, event);
}
Shawn Thye
  • 906
  • 2
  • 11
  • 23
1

The problem, as @Alex Vasilkov indicated, seems to do something with the drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); method.

None of the suggestions above did work for me. So I wanted to write my own solution. I digged the source code of DrawerLayout Class and tried overriding onKeyDown and onKeyUp methods, but the Back Button click is not getting triggered at all, if the Lock mode is LOCK_MODE_LOCKED_CLOSED. I think this is a bug.

So in my case, I needed to lock left navigation drawer only, not the right one. And I ended up calling drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.START); this method to lock my left navigation drawer instead of calling drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); this method, which locks both of the drawers and causes this back button bug.

So as a summary, drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); disables back button click somehow. Maybe only if you have two navigation drawers.

osayilgan
  • 5,873
  • 7
  • 47
  • 68
  • This hint disables closing of DrawerList when Back has been pressed, but OnBackPressed() also isn't called. – GSD.Aaz May 23 '16 at 15:15
1

After adding this line back button will manage to close DrawerLayout.

mDrawerLayout.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); 
Parag Chauhan
  • 35,760
  • 13
  • 86
  • 95
1

I had a very similar issue with an empty list in a fragment (wouldn't respond to back button press when the list was empty) and some of the solutions mentioned here helped me solving my issue.

The fragment causing the issue with the "onBackPressed()":

<TextView
   android:id="@android:id/empty"
   ... />
<ListView
   android:id="@android:id/list"
   android:layout_width="match_parent"
   android:layout_height="match_parent" />

The issue is similar in that when the list returned by the adapter is empty (@android:id/empty), the first view (TextView) doesn't seem to be "considered" as a focusable/focused view by Android (whereas the second view - ListView - is).

So pressing the back button wouldn't be registered by the view currently displayed and wouldn't be caught by my custom code in the fragment (instead closing the activity directly).

In my case, adding the following to onCreateView solved my issue (and allowed the back button press to be caught by the fragment even when the list is empty):

    View view = inflater.inflate(R.layout.fragment_content, container, false);
    view.setFocusableInTouchMode(true);
    view.requestFocus();
Pelpotronic
  • 550
  • 6
  • 11
-3

I know it is a bit late but still... this answer will help others

@Override
public void onBackPressed()
{
  if (mDrawerLayout.isOpen())
  mDrawerLayout.close();
else
  super.onBackPressed();
}
Gowtham Raj
  • 2,915
  • 1
  • 24
  • 38