10

I want to make my background Activity a little bit smaller while opening the Navigation Drawer, Simulate the effect that exists in the Airbnb application. I guess the best explanation would be a screenshot:

enter image description here

But the point is not to make the View just smaller, but to make it an animation that is synchronized to the Drawer Open/Close animation. So if you started to open the Drawer an in the middle decided to stop and go back, the background Activity scale will be affected accordingly.

How can this be done using the build in DrawerLayout? Is there some implementation for this?

halfer
  • 19,824
  • 17
  • 99
  • 186
Emil Adz
  • 40,709
  • 36
  • 140
  • 187

3 Answers3

19

You can perform this effect using the ActionBarDrawerToggle in the support library v4.

All you have to do is to Override onDrawerSlide method to retrieve the opening % of the drawer menu, and then scale your FrameLayout where your fragment is placed in.

Example with code:

main_layout.xml

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

Now in your Activity which holds the Drawer:

public class ConfigurerActivity extends ActionBarActivity 
{
    private DrawerLayout mDrawerLayout;
    private ListView mDrawerList;
    private ActionBarDrawerToggle mDrawerToggle;
    private FrameLayout frame;
    private float lastScale = 1.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)
            {
                float min = 0.9f;
                float max = 1.0f;
                float scaleFactor = (max - ((max - min) * slideOffset));

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) 
                {
                    frame.setScaleX(scaleFactor);
                    frame.setScaleY(scaleFactor);
                }
                else
                {               
                    ScaleAnimation anim = new ScaleAnimation(lastScale, scaleFactor, lastScale, scaleFactor, frame.getWidth()/2, frame.getHeight()/2);
                    anim.setDuration(0);
                    anim.setFillAfter(true);
                    frame.startAnimation(anim);

                    lastScale = scaleFactor;
                }
            }
        };

        mDrawerLayout.setDrawerListener(mDrawerToggle);

        // ... more of your code
    }
}

Note that i use 2 different methods to scale, because setScaleX/Y are not available in PRE - Honeycomb Android versions.

With this, you can set your own scaleFactor (i think 0.9f its small enough) or maybe try new effects (change color) based on the opening % of the drawer.

Hope it helps.

nsL
  • 3,722
  • 3
  • 23
  • 40
  • Thank you very much, it looks like the correct answer, my only problem is that in my application the NavDrawer Activity is basically a wrapper Activity for all the other Activities I have, so the layout I want to resize in not sitting in directly in the same Activity so I have no idea how to get it's instance. It's the frame instance in your example. I will see what I can do and soon accept you answer. – Emil Adz Nov 30 '13 at 14:16
  • Your solution is perfect, I tested it, made then needed changes in my code and it works as expected. Nice addition with the animation methods for different sdk versions although this I was already aware of but can be helpful to others. Thank you very much : ) – Emil Adz Nov 30 '13 at 16:29
  • i'm glad it has helped you! – nsL Dec 01 '13 at 09:55
  • If the icon drawer (ic_drawer) is not moving or toggle. Just remove your onDrawerClose & onDrawerOpen listeners and change to if statement of slideOffset which is refered here http://stackoverflow.com/a/23373562/1309629 – Cjames Jun 03 '14 at 10:17
  • This is useful, but can we scale without shifting the content to the right? When I decrease the min factor, the content feels like disappear. – Ralphilius Nov 06 '15 at 15:12
  • @Ralphilius the content is not being shifted, just scaled down. Check the 2 last parameters of the ScaleAnimation. Those are the Pivot values (X,Y) from where the scale takes place. Right now im using the center of the view, but you can play with those values and make the scale look different (like shrinking but one corner fixed on its place) – nsL Nov 06 '15 at 16:01
  • @nsL yeah, I understand it's being scaled down to center, I just wonder how to make it keep staying on the left side.. I was playing with min/max number but still not sure how this thing works.. – Ralphilius Nov 07 '15 at 00:07
1

Hey you can also give best effect for smaller activity . Check ResideMenu

demo with library.

Sachin
  • 528
  • 5
  • 17
0

if you have a look at the third-party library SlidingMenu, that should have everything you want.

The bit you are interested in is the behindScrollScale, which says this:

behindScrollScale - a float representing the relationship between the above view scrolling and the behind behind view scrolling. If set to 0.5f, the behind view will scroll 1px for every 2px that the above view scrolls. If set to 1.0f, the behind view will scroll 1px for every 1px that the above view scrolls. And if set to 0.0f, the behind view will never scroll; it will be static. This one is fun to play around with. Default is 0.25f.

panini
  • 2,026
  • 19
  • 21
  • I guess you might be right, but correctly I'm using the build in DrawerLayout, and I'm not really want to change this implementation but to add to it. Is there another way this can be done? – Emil Adz Nov 21 '13 at 12:21
  • not with the native DrawerLayout I don't think. [Google's design guidelines for DrawerLayout](http://developer.android.com/design/patterns/navigation-drawer.html) state that the content shouldn't move and the Drawer should appear over the content, so I doubt they would support something that breaks this. – panini Nov 21 '13 at 21:45