64

Just checked how to make menu with DrawerLayout here. But left side menu is moving on the front of main content. How can I set it to menu and main content move side by side(menu is pushing content to the right)?

Mr. Cat
  • 3,522
  • 2
  • 17
  • 26
  • The example in your link is ok. Key for overlaying instead of pushing the underlying content is the FrameLayout. Can you provide the layout you wrote? – jboi Dec 01 '13 at 11:59
  • 2
    You know it's supposed to do that though? That's what the system apps do and it's a suggested best practice when implementing a Drawer on Android. Is there any good reason you need it to push the content to the right? – wojtek.kalicinski Dec 02 '13 at 00:09

6 Answers6

174

If you dont want to use third-party libraries, you can implement it yourself just overriding the onDrawerSlide from the ActionBarDrawerToggle. There you can translate your framelayout view based on the opening % of your drawer.

Example with code:

<?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">

    <FrameLayout android:id="@+id/content_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>    

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

</android.support.v4.widget.DrawerLayout>

And here, override onDrawerSlide:

public class ConfigurerActivity extends ActionBarActivity 
{
    private DrawerLayout mDrawerLayout;
    private ListView mDrawerList;
    private ActionBarDrawerToggle mDrawerToggle;
    private FrameLayout frame;
    private float lastTranslate = 0.0f;

    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_layout);

        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.left_drawer);
        frame = (FrameLayout) findViewById(R.id.content_frame);

        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.drawable.ic_drawer, R.string.acc_drawer_open, R.string.acc_drawer_close) 
        {            
            @SuppressLint("NewApi")
            public void onDrawerSlide(View drawerView, float slideOffset)
            {
                super.onDrawerSlide(drawerView, slideOffset);
                float moveFactor = (mDrawerList.getWidth() * slideOffset);

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) 
                {
                    frame.setTranslationX(moveFactor);
                }
                else
                {
                    TranslateAnimation anim = new TranslateAnimation(lastTranslate, moveFactor, 0.0f, 0.0f);
                    anim.setDuration(0);
                    anim.setFillAfter(true);
                    frame.startAnimation(anim);

                    lastTranslate = moveFactor;
                }
            }
        };

        mDrawerLayout.setDrawerListener(mDrawerToggle);

        // ... more of your code
    }
}

Since setTranslationX is not available in pre-honeycomb android versions, i managed it using TranslateAnimation for lower version devices.

Hope it helps!

nsL
  • 3,722
  • 3
  • 23
  • 40
  • 13
    this really helped me. Since I have navigation drawer from both sides I just had to put -- if (drawerView.getId() == R.id.right_drawer) slideOffset *= -1; -- on top of onDrawerSlide method – kjurkovic Dec 19 '13 at 09:34
  • 1
    on this area the main layout will move further to the right and not be visible. if you guys want to move just half of it, you can divide it by two. float moveFactor = (mDrawerList.getWidth() * slideOffset) / 2 – Rye Feb 11 '14 at 06:28
  • That's basically the same thing what ContentDisplayDrawerToggle is doing.:) – Nikola Despotoski Feb 17 '14 at 18:27
  • @nsL -this seems helpful but can you please tell me how i can use this above class in my code , b'coz i'm not using any toggle button to slide , i'm using navigation drawer(provided by android). – Manish Sep 10 '14 at 09:14
  • @nsL It worked for me but when I am changing the orientation while drawer is opened then it is not moving the content and the drawer is still opened. So I need when drawer is opened and I change the orienation then the content layout should be moved. Suggest me the solution. – Araju Nov 07 '14 at 11:07
  • The drawer icon stops animating when this code is added. Instead of smoothly sliding in and out it just instantly changes when opened/closed? – JanBo Feb 23 '15 at 21:41
  • 5
    Just add call to super.onDrawerSlide and it will move with animation again :D – JanBo Feb 23 '15 at 21:46
  • @Hawk yeah the ActionBarActivity is deprecated now, use AppCompatActivity instead. i will update the example later – nsL Oct 05 '15 at 15:32
  • @nsL Hi thnx for the answer. Its working perfectly for me. But one small issue. I am getting a gap(white screen) in between the drawer and action bar while sliding the drawer. How to remove that gap? I want that both to be attached while sliding. – Encipherer Mar 09 '16 at 06:57
  • @IndependentDev hard to know without checking your code, but might be that you are increasing also the Y coordinate when translating? Is the gap always same size? – nsL Mar 09 '16 at 15:46
  • @nsL No I am not changing anything, I just used your code. And s the space is always same. I just wanna move the action bar along with drawer without space – Encipherer Mar 10 '16 at 05:23
  • 1
    its moved to the other side ? i add - for it its move now to correct side but more than slideOffset ?! – Максим Зубков Jun 18 '16 at 01:49
  • 1
    Thank you so much..... its work for me.. i googled from last day. but every one say use slidemenu library. But i dont wanna add it. thank you From my side +100 – Vipin Jain Jul 05 '16 at 09:23
  • In my case this disable the arrow/burger animation. just added super.onDrawerSlide(drawerView, slideOffset); to recover it. thank you very much for the snippet – crgarridos Aug 29 '16 at 08:11
  • 1
    It worked for me. Note though, that if the left drawer has some padding, part of the content frame will be hidden when the drawer opens; seems like mDrawerList.getWidth() doesn't take padding into account. A workaround would be to add padding on the drawer's child views. – ris8_allo_zen0 Sep 07 '16 at 08:35
  • Help me to make this Fraction and usage of variables, i want to animate from right to left than ?? – Abdul Rahman Majeed May 28 '17 at 23:27
  • Perfect solution! – Hantash Nadeem Jun 11 '22 at 22:16
9

You might want to use this library of Drawer Toggles I wrote.

I'm sure you will find ContentDisplaceDrawerToggle handy:

ContentDisplaceDrawerToggle mContentDisplaceToggle = new ContentDisplaceDrawerToggle(this, mDrawerLayout, R.id.content_frame);    
mDrawerLayout.setDrawerListener(mContentDisplaceToggle);

ContentDisplaceDrawerToggle does exactly what you are saying. It moves the content view as you slide in/out the DrawerLayout.

Example image

If you want to combine different toggles you can use the ActionBarToggleWrapper or DrawerToggleWrapper

Usage options are given in the read me file.

Nikola Despotoski
  • 49,966
  • 15
  • 119
  • 148
  • 1
    Is it possible that the drawer shifts the ActionBar when it opened? – cmcromance Apr 30 '14 at 14:34
  • 1
    @cmcromance not the native ActionBar, but you can use drawer with a custom action bar (a view simulating an action bar) and you move it as a view when the drawer is opened – nsL Sep 18 '14 at 16:52
  • 1
    @Nikola It says "Import the library project and set it to your project.". How do you do that? – Marshall Mar 11 '15 at 15:45
  • could i use it within Activity not ActionBarActivity? – Antwan Jun 27 '15 at 12:07
  • 1
    @V.Kalyuzhnyu Why would you need native code for simple translation? If it doesn't fit your needs feel free to write your own or keep on searching. – Nikola Despotoski Jan 04 '16 at 11:35
  • Translation require much resources. And often there are freezes especially on emulators. i'm looking at SlidingMenu libary now – Vlad Jan 04 '16 at 13:04
  • Logic for Gravity.RIGHT is flawed. Should just be: `translationX = mGravity == GravityCompat.START || mGravity == Gravity.RIGHT ? translationX : -translationX;` – Anthony Mar 01 '16 at 21:02
3

The answer is pretty simple: First create a NavigationDrawer Activity.

<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.v4.widget.DrawerLayout>

Then open app_bar_main.layout and assign an id to the parent layout.

Lets say you gave android:id="@+id/appBarMain"

Just declare the parent viewgroup in MainActivity.class with respective id :

and add a drawer listener to the drawerlayout like below:

drawer.addDrawerListener(new DrawerLayout.DrawerListener() {
            @Override
            public void onDrawerSlide(View drawerView, float slideOffset) {
                float moveFactor = 0;
                moveFactor = (drawerView.getWidth() * slideOffset);

                appBarMain.setTranslationX(moveFactor);
            }

            @Override
            public void onDrawerOpened(View drawerView) {

            }

            @Override
            public void onDrawerClosed(View drawerView) {

            }

            @Override
            public void onDrawerStateChanged(int newState) {

            }
        });

Add a translation code in OnDrawerSlide() method like above and that's it.

1

Here is working code...

ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, mDrawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) {
 @Override
 public void onDrawerSlide(View drawerView, float slideOffset) {
    super.onDrawerSlide(drawerView, slideOffset);
    mContainerFrame.setTranslationX(slideOffset * drawerView.getWidth());
    mDrawerLayout.bringChildToFront(drawerView);
    mDrawerLayout.requestLayout();
    //below line used to remove shadow of drawer
    mDrawerLayout.setScrimColor(Color.TRANSPARENT);
  }//this method helps you to aside menu drawer
 };
Ness Tyagi
  • 2,008
  • 24
  • 18
0

OP got the answer. But for someone else that wants that effect, can use SlidingPaneLayout. It's designed for this purpose.

In XML file:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SlidingPaneLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@id/mainFrame"
    style="@style/MP.mainFrame" >


    <!--****************************Right Pane ****************************-->
    <LinearLayout style="@style/searchLayout">
        <android.support.v4.widget.NestedScrollView style="@style/MP">
            <LinearLayout style="@style/MP.verticalLinearLayout">


            </LinearLayout>
        </android.support.v4.widget.NestedScrollView>
    </LinearLayout>
    <!--****************************Right Pane ****************************-->

    <!--****************************Left Pane ****************************-->
<FrameLayout style="@style/MP.mainLayout">
    <LinearLayout android:id="@id/fragmentContainer" style="@style/MP.fragmentContainer"/>

    <android.support.v7.widget.Toolbar style="@style/toolbar">
        <ir.tooskar.excomponents.ExtendedTextView android:id="@id/appTitle" style="@style/WC.appTitle"/>
        <ir.tooskar.excomponents.ExtendedTextView android:id="@id/appBarSearchIcon" style="@style/WC.appBarSearchIcon"/>
    </android.support.v7.widget.Toolbar>
</FrameLayout>        <!--****************************Left Pane ****************************-->

There are two panes, right and left, stick together and thus move together. For me, the left pane is the main pane and the right is hidden with a toggle icon to display it. (A view with id appBarSearchIcon).

Remember, there is one viewgroup named, SlidingPaneLayout that has just two children, The Left and The Right.

And important part in the activity:

        slidingPaneLayout = (SlidingPaneLayout) findViewById(R.id.mainFrame);
//        Sets a color for covering left pane(Main Pane)
        slidingPaneLayout.setSliderFadeColor(ContextCompat.getColor(context, R.color.searchPaneFadeColor));

//        The listener for Opening the Right pane(Hidden pane)
        findViewById(R.id.appBarSearchIcon).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view){
                slidingPaneLayout.openPane();
            }
        });

Closing the right pane is done by the API, just like Navigation Drawer.

Arash
  • 696
  • 8
  • 24
-3

In second layout set

android:layout_gravity="start"
Infinite Recursion
  • 6,511
  • 28
  • 39
  • 51
Lalit kumar
  • 2,377
  • 1
  • 22
  • 17