You can do this by translating and scaling the content View
in the onDrawerSlide()
method of a DrawerListener
on your DrawerLayout
. Since the content View
itself is resizing, and there’s a separate TextView
that appears in the bottom right corner, we’ll stick both of these in another holder ViewGroup
. If that label TextView
isn’t needed, the holder ViewGroup
can be omitted, as well.
A basic DrawerLayout
setup for the example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
<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" android:background="#222222"> <RelativeLayout android:id="@+id/holder" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="#E97411" /> <ImageView android:id="@+id/main_content" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="#EEEEEE" android:src="@drawable/ic_launcher" /> </LinearLayout> <TextView android:id="@+id/label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:visibility="gone" android:textSize="26dp" android:text="My App" /> </RelativeLayout> <android.support.design.widget.NavigationView android:id="@+id/navigation_view" android:layout_width="240dp" android:layout_height="match_parent" android:layout_gravity="left" android:background="#555555" /> </android.support.v4.widget.DrawerLayout> |
The example Activity
shows the standard View
initializations, and the DrawerListener
that is actually doing the work.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
public class MainActivity extends AppCompatActivity { private static final float END_SCALE = 0.7f; private DrawerLayout drawerLayout; private NavigationView navigationView; private Toolbar toolbar; private TextView labelView; private View contentView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); navigationView = (NavigationView) findViewById(R.id.navigation_view); toolbar = (Toolbar) findViewById(R.id.toolbar); labelView = (TextView) findViewById(R.id.label); contentView = findViewById(R.id.content); toolbar.setNavigationIcon(new DrawerArrowDrawable(this)); toolbar.setNavigationOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (drawerLayout.isDrawerOpen(navigationView)) { drawerLayout.closeDrawer(navigationView); } else { drawerLayout.openDrawer(navigationView); } } } ); drawerLayout.setScrimColor(Color.TRANSPARENT); drawerLayout.addDrawerListener(new DrawerLayout.SimpleDrawerListener() { @Override public void onDrawerSlide(View drawerView, float slideOffset) { labelView.setVisibility(slideOffset > 0 ? View.VISIBLE : View.GONE); // Scale the View based on current slide offset final float diffScaledOffset = slideOffset * (1 - END_SCALE); final float offsetScale = 1 - diffScaledOffset; contentView.setScaleX(offsetScale); contentView.setScaleY(offsetScale); // Translate the View, accounting for the scaled width final float xOffset = drawerView.getWidth() * slideOffset; final float xOffsetDiff = contentView.getWidth() * diffScaledOffset / 2; final float xTranslation = xOffset - xOffsetDiff; contentView.setTranslationX(xTranslation); } @Override public void onDrawerClosed(View drawerView) { labelView.setVisibility(View.GONE); } } ); } } |
The example uses a SimpleDrawerListener
, but the onDrawerSlide()
method can be overridden similarly in an ActionBarDrawerToggle
, if using that. The super
method would need to be called, in that case, to preserve the hamburger-arrow animation.
Do note that DrawerLayout
retains the drawer state during Activity
recreation, so you might need to account for this when handing orientation changes, etc.