68

I have an application, in which i want to implement a double drawer - one from the left and one from the right. Left drawer is for app navigation, right drawer is for result filtering.

So, the layout is like this:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/light_grey"
        android:orientation="vertical">

        <GridView
            android:id="@+id/gridview"
            style="@style/GridViewStyle"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:gravity="center"
            android:horizontalSpacing="7dp"
            android:stretchMode="columnWidth"
            android:verticalSpacing="7dp" />
    </LinearLayout>

    <ListView
        android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#111"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp" />

    <ListView
        android:id="@+id/right_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="end"
        android:background="#111"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp" />
</android.support.v4.widget.DrawerLayout>

You can clearly see here "left_drawer" and "right_drawer", and their respective gravity - "start" and "end" And this actually works! You can pull them both out.

The problem is, when i implement the DrawerToggle - it only opens the left drawer, and does not close the right one, so if the right drawer is opened and i press the DrawerToggle button - the left drawers opens ALSO, and overlaps the right drawer.

There are a couple of solutions i'am trying to get:

  1. Make the same DrawerToggle button on the right side, with the same behavior and animation as the left side.
  2. Make the drawer on the opposite side of the drawer i am trying to open - automatically close (if the left drawer is open and i press the toggle of the right drawer and vise-versa).

And i haven't figured how to do that, because DrawerToggle accepts the DrawerLayout itself as a parameter, and not the individual drawers...

I am using the Support Library.

Anyone have any ideas? Thank you in advance.

r4jiv007
  • 2,974
  • 3
  • 29
  • 36
ExiRouS
  • 803
  • 1
  • 7
  • 9

8 Answers8

36

Here is the code for a Double Drawer Activity than can be extended by other activities to implement the double drawer, assuming they have a layout like the one propposed by OP.

    public class DoubleDrawerActivity extends ActionBarActivity {

    private DrawerLayout mDrawerLayout;
    private ActionBarDrawerToggle mDrawerToggle;
    private View mLeftDrawerView;
    private View mRightDrawerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeButtonEnabled(true);
    }

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

        if(mDrawerLayout == null || mLeftDrawerView == null || mRightDrawerView == null || mDrawerToggle == null) {
            // Configure navigation drawer
            mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
            mLeftDrawerView = findViewById(R.id.left_drawer);
            mRightDrawerView = findViewById(R.id.right_drawer);
            mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.drawable.ic_navigation_drawer, R.string.drawer_open, R.string.drawer_close) {

                /** Called when a drawer has settled in a completely closed state. */
                public void onDrawerClosed(View drawerView) {
                    if(drawerView.equals(mLeftDrawerView)) {
                        getSupportActionBar().setTitle(getTitle());
                        supportInvalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
                        mDrawerToggle.syncState();
                    }
                }

                /** Called when a drawer has settled in a completely open state. */
                public void onDrawerOpened(View drawerView) {
                    if(drawerView.equals(mLeftDrawerView)) {
                        getSupportActionBar().setTitle(getString(R.string.app_name));
                        supportInvalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
                        mDrawerToggle.syncState();
                    }                   
                }

                @Override
                public void onDrawerSlide(View drawerView, float slideOffset) {
                    // Avoid normal indicator glyph behaviour. This is to avoid glyph movement when opening the right drawer
                    //super.onDrawerSlide(drawerView, slideOffset);
                }
            };

            mDrawerLayout.setDrawerListener(mDrawerToggle); // Set the drawer toggle as the DrawerListener
        }
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);

        // Sync the toggle state after onRestoreInstanceState has occurred.
        mDrawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        mDrawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {

        // If the nav drawer is open, hide action items related to the content view
        for(int i = 0; i< menu.size(); i++)
            menu.getItem(i).setVisible(!mDrawerLayout.isDrawerOpen(mLeftDrawerView));

        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        switch(item.getItemId()) {
            case android.R.id.home:
                mDrawerToggle.onOptionsItemSelected(item);

                if(mDrawerLayout.isDrawerOpen(mRightDrawerView))
                    mDrawerLayout.closeDrawer(mRightDrawerView);

                return true;
        }

        return super.onOptionsItemSelected(item);
    }
}
Shailendra Madda
  • 20,649
  • 15
  • 100
  • 138
Daniel López Lacalle
  • 6,715
  • 3
  • 25
  • 23
  • Forgot to say that this makes use of the v7 support appcompat lib http://developer.android.com/tools/support-library/features.html – Daniel López Lacalle Jan 05 '14 at 22:57
  • 6
    Also, if you want the glyphe to move for the left drawer only, you can do that in the onDrawerSlide method : if(drawerView == leftDrawer) super.onDrawerSlide(drawerView, slideOffset); – Stephane Mathis Feb 05 '14 at 19:34
  • 1
    @DanielLópezLacalle Thanks for your answer.. i have followed your code and it doesnot give any errors but even after that it dosent shows anything in the right side of my action bar.. nothing at all. – Abstract Dec 11 '14 at 20:51
  • FYI additional views with gravity right or left (e.g., a FloatingActionButton) should not be added at the listview level or it will lead to an error similar to that one: `Child drawer has absolute gravity RIGHT but this DrawerLayout already has a drawer view along that edge` – Zach Aug 08 '17 at 07:32
25

You can call it like this in a ToggleButton's handler for example :

mDrawerLayout.openDrawer(mDrawer);
mDrawerLayout.closeDrawer(mDrawer);

Where mDrawer is a reference to the specific drawer you need to open (be it a view or a layout), in your case, the actual ListView you wish to display.

Armel Larcier
  • 15,747
  • 7
  • 68
  • 89
11

You can use NavigationView from material design.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main"
        app:menu="@menu/activity_main_drawer" />

    <android.support.design.widget.NavigationView
        android:id="@+id/nav_view2"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="end"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main"
        app:menu="@menu/activity_main_drawer1" />

</android.support.v4.widget.DrawerLayout>
Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Gunaseelan
  • 14,415
  • 11
  • 80
  • 128
6

Here is my short solution for all who want to prevent the animation of drawer indicator if they swipe the right view. Simply implement the onDrawerSlide Method like this.

mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.drawable.ic_drawer_white, 0, 0) {

    @Override
    public void onDrawerClosed(View view) {
       invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
    }

    @Override
    public void onDrawerOpened(View drawerView) {
       invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
    }

    @Override
    public void onDrawerSlide(View drawerView, float slideOffset) {
       if (drawerView == mSlidingMenuNavigationList) {
           super.onDrawerSlide(drawerView, slideOffset);
       }
       else {
          // do nothing on all other views
       }
    }
};
Kai Burghardt
  • 1,493
  • 16
  • 16
  • 1
    Using that approach, the animation stops but the glyph (icon) now jumps to the position that it would normally slide to. what do you do about preventing the move all together? – Chase Florell Apr 12 '14 at 03:55
5

Use the gravity constant (Gravity.LEFT or Gravity.RIGHT) of whatever drawer you want to close (as you open the other one) in onOptionsItemSelected() as shown below.

public boolean onOptionsItemSelected(MenuItem item) {
    if (mDrawerToggle.onOptionsItemSelected(item)) {

       // Close the right side drawer if visible
       if(mDrawerLayout.isDrawerVisible(Gravity.RIGHT)) {
           mDrawerLayout.closeDrawer(Gravity.RIGHT);
       }
       return true;
    }

    // Regular stuff
    switch (item.getItemId()) {
    case R.id.action_example:
        Toast.makeText(getActivity(), "Example action.", Toast.LENGTH_SHORT).show();
        return true;
    }

    return super.onOptionsItemSelected(item);
}

mDrawerToggle = Listener object implementing DrawerLayout.DrawerListener
See: http://developer.android.com/reference/android/support/v4/app/ActionBarDrawerToggle.html

Himanshu Likhyani
  • 4,490
  • 1
  • 33
  • 33
0

I have solved adding this code in the onOptionsItemSelected method:

switch (item.getItemId()) {
    case android.R.id.home:
        if (mDrawerLayout.isDrawerOpen(mDrawerList_right)){
            mDrawerLayout.closeDrawer(mDrawerList_right);
        }
        mDrawerLayout.openDrawer(mDrawerList_left);
    }
    break;
case R.id.action_drawer:
        if (mDrawerLayout.isDrawerOpen(mDrawerList_left)){
            mDrawerLayout.closeDrawer(mDrawerList_left);
        }
        mDrawerLayout.openDrawer(mDrawerList_right);
    }
default:
    break;
}

I have added an action button and overrided the home button of the actionbar

Community
  • 1
  • 1
0

make a custom item and add it the right, pass to it the right drawer.

final ToggleButton ic_nav = (ToggleButton) customNav.findViewById(R.id.ic_nav);

        ic_nav.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View arg0)
            {
                if ( mDrawerLayout.isDrawerOpen(mDrawerList) && arg0.isSelected()) {
                    mDrawerLayout.closeDrawer(mDrawerList);
                    arg0.setSelected(false);
                }
                else if (!mDrawerLayout.isDrawerOpen(mDrawerList) && !arg0.isSelected()){
                    mDrawerLayout.openDrawer(mDrawerList);
                    ic_nav.setSelected(false);
                    arg0.setSelected(true);
                }
            }
        });
mhdtouban
  • 851
  • 2
  • 11
  • 20
0

You can show two navigation views to the same drawer as:

<androidx.drawerlayout.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false">
   <com.google.android.material.navigation.NavigationView
    android:id="@+id/NAVIGATION_VIEW_LEFT"
    android:layout_width="270dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"/>
   <com.google.android.material.navigation.NavigationView
        android:id="@+id/NAVIGATION_VIEW_RIGHT"
        android:layout_width="200dp"
        android:layout_height="match_parent"
        android:layout_gravity="right"/>
</androidx.drawerlayout.widget.DrawerLayout>

And for activity do this:

actionBarDrawerToggle = new ActionBarDrawerToggle(context, drawerLayout, R.string.nav_open, R.string.nav_close);
        // pass the Open and Close toggle for the drawer layout listener
        // to toggle the button
        drawerLayout.addDrawerListener(actionBarDrawerToggle);
        actionBarDrawerToggle.syncState();
        nav_drawer_left_Iv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                drawerLayout.openDrawer(GravityCompat.START);
            }
        });
        nav_drawer_right_Iv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                drawerLayout.openDrawer(GravityCompat.END);
            }
        });
VIVek
  • 121
  • 1
  • 4