How to implement a DrawerLayout with a visible handle
Asked Answered
D

2

32

I have successfully implemented a NavigationDrawer for my application.

My app displays a drawer that opens on the left of the screen.

My problem is I need to add a button on the left. That button might be clicked or swiped to open the left drawer. That I can do.

But the button is supposed to look like it's a part of the drawer that would overflow into the screen.

That means the button should slide simultaneously as the drawer opens and closes.

CLOSED STATE :

enter image description here

OPENING STATE

enter image description here

I tried adding the button into the left drawer's layout, but it seems you can't make stuff appear outside of its boundaries, and the drawer will always get completely hidden when you close it.

Now I'm trying adding it to add a button to the main DrawerLayout and make it align to the right of the left drawer... But no luck... It looks like a DrawerLayout can't have more than two children...

Any help will be appreciated.

I'm using the Support library (v4)

[EDIT] And I am supporting API level 8... So can't use ImageView.setTranslationX or View.OnAttachStateChangeListener

Dinnerware answered 26/7, 2013 at 14:38 Comment(1)
My own (accepted) answer is the solution I chose.Dinnerware
D
6

I found a way of doing this pretty easily thanks to the Aniqroid library written by Mobistry (SO pseudo)

I use the SlidingTray class which is a copy of android SlidingDrawer but lets you position the drawer to any corner of the screen.

I declared the element via xml

<com.sileria.android.view.SlidingTray 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer"
    android:layout_width="match_parent"
    android:layout_height="270dp"
    android:content="@+id/content"
    android:handle="@+id/handle" >

    <ImageView
        android:id="@+id/handle"
        android:layout_width="320dp"
        android:layout_height="24dp"
        android:background="@drawable/tray_btn" />

    <LinearLayout
        android:id="@+id/content"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="fill_vertical"
        android:orientation="vertical" >
    </LinearLayout>

</com.sileria.android.view.SlidingTray>

And just had to call

Kit.init(this);

in my main Activity before inflating the layout.

I thank aniqroid devs!

https://code.google.com/p/aniqroid/

Dinnerware answered 26/8, 2013 at 7:31 Comment(1)
I've got a bunch of errors trying to integrate this libraryAntirachitic
C
12

It's quite tricky.

I think this is similar to what is done to the drawer handle in new Google Maps app. Don't take my word, not sure. :)

I have written toggle that stays on the edge of the Activity content view. When the DrawerLayout is dragged, I translated the view on the x-axis by the amount of the minimal child (which is DrawerLayout content view) minus the shadow (if any). Since the shadow casted + content view of the DrawerLayout gives the full measured width of the entire drawer.

I quickly multiply the slided offset and the minimal child and find the x translation.

[Edit: Code has been removed for readability and it has been moved to the link provided below]

In your activity:

mDrawerToggle = new DrawerLayoutEdgeToggle(
    this, 
    mDrawerLayout, 
    R.drawable.ic_launcher, 
    R.drawable.ic_launcher,
    Gravity.LEFT, 
    true) {

        @Override
        public void onDrawerClosed(View view) {
            super.onDrawerClosed(view); //must call super
        }

        @Override
        public void onDrawerOpened(View view) {
            super.onDrawerOpened(view); //must call super
        }

        @Override
        public void onDrawerSlide(View view, float slideOffset) {
            super.onDrawerSlide(view, slideOffset); //must call super

        }
    };
mDrawerLayout.setDrawerListener(mDrawerToggle);

Creativity boost: You can add more cosmetics like distance from ActionBar which you can set as margin to the handle.

Also you can mimic "single-zipper effect" by moving the handle up/down along left/right just by translating on the Y axis. :)

Edit: Its available on my GitHub here

Edit 2: For those that can't get the handle appear at the beginning just use mDrawerToggle.setVerticalPostionOffset(0)

Cadency answered 19/8, 2013 at 3:15 Comment(6)
Thanks a lot. I'm not sure I can adapt your solution though since I need to support API level 8 as I wrote in my edit. Any ideas for that? Will try it out.Dinnerware
@ArmelLarcier I have worked around to give also support for older version <= 11. I didn't have time to add NineOldAndroids animation library. If you have time, feel free to create pull request and add that. See my github for the changes you asked.Cadency
Could not get this to work properly with your lib, handle wasn't showing up but when touching certain parts of the screen (no where near the left side where the drawer usually opens) the drawer did seem to appear all of a sudden. I also didn't want to use slidingDrawer since I feel that widget is really sluggish. In the end with just the nineoldandroids lib I was able to achieve the desired result by just placing another view next to the drawer and animating the x value at the same pace as the drawer was moving.Reign
Thats basically the same what the lib does. Probably there is one odd behaviour when you do not set vertical position of the handle. I will fix it when I have time. For those that experience this just use setVerticalPostionOffset(0)Cadency
Can u plz add some example activity? Where to put Icon of handler?Dogmatist
on what object this method setVerticalPostionOffset(0) should be called?Present
D
6

I found a way of doing this pretty easily thanks to the Aniqroid library written by Mobistry (SO pseudo)

I use the SlidingTray class which is a copy of android SlidingDrawer but lets you position the drawer to any corner of the screen.

I declared the element via xml

<com.sileria.android.view.SlidingTray 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer"
    android:layout_width="match_parent"
    android:layout_height="270dp"
    android:content="@+id/content"
    android:handle="@+id/handle" >

    <ImageView
        android:id="@+id/handle"
        android:layout_width="320dp"
        android:layout_height="24dp"
        android:background="@drawable/tray_btn" />

    <LinearLayout
        android:id="@+id/content"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="fill_vertical"
        android:orientation="vertical" >
    </LinearLayout>

</com.sileria.android.view.SlidingTray>

And just had to call

Kit.init(this);

in my main Activity before inflating the layout.

I thank aniqroid devs!

https://code.google.com/p/aniqroid/

Dinnerware answered 26/8, 2013 at 7:31 Comment(1)
I've got a bunch of errors trying to integrate this libraryAntirachitic

© 2022 - 2024 — McMap. All rights reserved.