Navigation Drawer: set as always opened on tablets

I am using the Navigation Drawer pattern from the support library:
http://developer.android.com/training/implementing-navigation/nav-drawer.html

I was trying to set it as always opened on tablet (as a side menu)

  • Android: Executing code only on first run and every subsequent upgrade
  • Search locations inside a particular city in Google Places Apis
  • Send email via gmail
  • How can I read the app version defined in the manifest file programmically?
  • PercentRelativeLayout, how to set the height programmatically
  • How to wrap lengthy text in a spinner
  • enter image description here

    Is that something possible with the current implementation, or do we have to create a new layout and a new structure with a Listview instead of reusing the same code?

  • Kalman Filter for Android
  • How to import or copy images to the “res” folder in Android Studio?
  • Android XML: android:elevation vs. app:elevation
  • Code snippets in android studio
  • Why it says that “Cannot refer to a non-final variable i inside an inner class defined in a different method”?
  • What font file types does Android support?
  • 5 Solutions collect form web for “Navigation Drawer: set as always opened on tablets”

    Based on the idea of larger devices could have different layout files, I have created the follow project.

    https://github.com/jiahaoliuliu/ABSherlockSlides

    HighLights:

    Since the drawer of a large device is always visible, there is not need to have an drawer. Instead, a LinearLayout with two elements with the same name will be enough.

    <LinearLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:orientation="horizontal">
         <ListView
                 android:id="@+id/listview_drawer"
                 android:layout_width="@dimen/drawer_size"
                 android:layout_height="match_parent"
                 android:layout_gravity="start"
                 android:choiceMode="singleChoice"
                 android:divider="@android:color/transparent"
                 android:dividerHeight="0dp"
                 android:background="@color/drawer_background"/>
        <FrameLayout
                android:id="@+id/content_frame"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_marginLeft="@dimen/drawer_content_padding"
                />
    </LinearLayout>
    

    Because we don’t have the drawer in the layout file, when the app try to find the element in the layout, it will return null. So, there is not need to have an extra boolean to see which layout is using.

    DrawerLayout mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
    
    if (mDrawerLayout != null) {
        // Set a custom shadow that overlays the main content when the drawer opens
        mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
        // Enable ActionBar app icon to behave as action to toggle nav drawer
        getSupportActionBar().setHomeButtonEnabled(true);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    
        // ActionBarDrawerToggle ties together the proper interactions
        // between the sliding drawer and the action bar app icon
        mDrawerToggle = new ActionBarDrawerToggle(
                this,
                mDrawerLayout,
                R.drawable.ic_drawer,
                R.string.drawer_open,
                R.string.drawer_close) {
    
            public void onDrawerClosed(View view) {
                super.onDrawerClosed(view);
            }
    
            public void onDrawerOpened(View drawerView) {
                // Set the title on the action when drawer open
                getSupportActionBar().setTitle(mDrawerTitle);
                super.onDrawerOpened(drawerView);
            }
        };
    
        mDrawerLayout.setDrawerListener(mDrawerToggle);
    }
    

    Here is the example to use it as boolean.

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        if (mDrawerLayout != null) {
            mDrawerToggle.syncState();
        }
    }
    
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (mDrawerLayout != null) {
            // Pass any configuration change to the drawer toggles
            mDrawerToggle.onConfigurationChanged(newConfig);
        }
    }
    

    Building upon CommonsWare’s answer you can do this with a couple of adjustments. The first is setting the following three lines:

    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
    drawerLayout.setScrimColor(getResources().getColor(R.color.drawerNoShadow));
    isDrawerLocked = true;
    

    The drawerNoShadow color can just be a no-alpha color (like 0x00000000). That gets you an open drawer with no background overlay.

    The second thing you need to do is adjust the padding_left value of your FrameLayout. For this purpose you can setup a dimension to control this (0dp by default) – in this example R.dimen.drawerContentPadding. You will also need an R.dimen.drawerSize value that will be the width of the DrawerLayout.

    This allows you to check the paddingLeft value of the FrameLayout to call those lines.

    FrameLayout frameLayout = (FrameLayout)findViewById(R.id.content_frame);
    if(frameLayout.getPaddingLeft() == (int)getResources().getDimension(R.dimen.drawerSize) {
        drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
        drawerLayout.setScrimColor(getResources().getColor(R.color.drawerNoShadow));
        isDrawerLocked = true;
    }
    

    You can then wrap all the functionality you don’t want to enable in an if(!isDrawerLocked) statement. This will include:

    • drawerLayout.setDrawerListener(drawerToggle);
    • getActionBar().setDisplayHomeAsUpEnabled(true);

    Lastly you do need to setup alternate layouts for the views with a static drawer. An example is:

    <FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.support.v4.widget.DrawerLayout
    
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <!-- The navigation drawer -->
        <ListView
            android:id="@+id/left_drawer"
            android:layout_width="@dimen/drawerSize"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:choiceMode="singleChoice"
            android:divider="@android:color/transparent"
            android:dividerHeight="0dp"
            android:background="#111"/>
    
    </android.support.v4.widget.DrawerLayout>
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginLeft="@dimen/drawerContentPadding"/>
    

    The beauty here is you can then control all of the logic by setting up alternate dimen.xml files for the devices you want to target and the only thing you need to change is the value of drawerContentPadding and offer the modified layouts.

    NOTE: I ended up using margin_left instead of padding_left since in the new layout it overlays the drawer. See a more in-depth blog post about the technique at http://derekrwoods.com/2013/09/creating-a-static-navigation-drawer-in-android/

    Try setDrawerLockMode() to lock the drawer open on large-screen devices.

    As I noted in a comment, I don’t think that DrawerLayout is designed for your scenario (though it’s not a bad idea, IMHO). Either use a different layout that hosts the same ListView and content, or perhaps download and modify your own copy of DrawerLayout that, on large-screen devices, slides the content over when opened rather than overlaps it.

    based on @methodin sample code and @CommonsWare idea

    Here is the full code (Android studio only)

    Previous answers are good, but I faced some problems while implementing them in my project, so I want to share my solution.
    First of all, we need to define a custom drawer:

    public class MyDrawerLayout extends DrawerLayout {
        private boolean m_disallowIntercept;
    
        public MyDrawerLayout (Context context) {
            super(context);
        }
    
        @Override
        public boolean onInterceptTouchEvent(final MotionEvent ev) {
            // as the drawer intercepts all touches when it is opened
            // we need this to let the content beneath the drawer to be touchable
            return !m_disallowIntercept && super.onInterceptTouchEvent(ev);
        }
    
        @Override
        public void setDrawerLockMode(int lockMode) {
            super.setDrawerLockMode(lockMode);
            // if the drawer is locked, then disallow interception
            m_disallowIntercept = (lockMode == LOCK_MODE_LOCKED_OPEN);
        }
    }
    

    Then we put it in a basic activity layout (without arbitrary layouts from previous answers) like this:

    <MyDrawerLayout 
        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">
    
        <!--We must define left padding for content-->
        <FrameLayout
            android:id="@+id/content_frame"
            android:paddingStart="@dimen/content_padding"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    
        <android.support.design.widget.NavigationView
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:fitsSystemWindows="true"
            app:menu="@menu/menu_nav" />
    
    </MyDrawerLayout>
    

    Content padding here is 0dp in portrait orientation and about 300dp in landscape for NavigationView (figured out empirically). We define them in appropriate values folders:

    values/dimens.xml

    <dimen name="content_padding">0dp</dimen>
    

    values-land/dimens.xml

    <dimen name="content_padding">300dp</dimen>
    

    Finally, we lock the drawer in the activity:

        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
            mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
            mDrawerLayout.setScrimColor(0x00000000); // or Color.TRANSPARENT
            isDrawerLocked = true;
        } else if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
            mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
            mDrawerLayout.setScrimColor(0x99000000); // default shadow
            isDrawerLocked = false;
        }
    
    Android Babe is a Google Android Fan, All about Android Phones, Android Wear, Android Dev and Android Games Apps and so on.