Andy Strife Andy Strife - 6 months ago 40
Android Question

Moving and resizing DrawerLayout's content on sliding

I just came across this app and saw this custom animation for a

DrawerLayout
.
I'm guessing it has to take a screenshot first, then draw a custom
View
in the
Activity
, but I'm not sure about that, nor the details.
Does anyone know how to do this?

enter image description here

Answer

You can do this by moving and resizing 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.

The example layout has an ImageView for the main content.

<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 just shows the standard View initializations, and the DrawerListener that is actually doing the work

public class MainActivity extends AppCompatActivity {

    private DrawerLayout drawerLayout;
    private NavigationView navigationView;
    private Toolbar toolbar;
    private TextView labelView;
    private View holderView, 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);
        holderView = findViewById(R.id.holder);
        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 drawer, float slideOffset) {
                    labelView.setVisibility(slideOffset > 0 ? View.VISIBLE : View.GONE);

                    contentView.setX(navigationView.getWidth() * slideOffset);
                    RelativeLayout.LayoutParams lp =
                        (RelativeLayout.LayoutParams) contentView.getLayoutParams();
                    lp.height = drawerLayout.getHeight() -
                        (int) (drawerLayout.getHeight() * slideOffset * 0.3f);
                    lp.topMargin = (drawerLayout.getHeight() - lp.height) / 2;
                    contentView.setLayoutParams(lp);
                }

                @Override
                public void onDrawerClosed(View drawerView) {
                    labelView.setVisibility(View.GONE);
                }
            }
        );
    }
}