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:
<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.
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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…