更新:
从支持库 24.0.0 开始,无需任何变通方法即可实现此操作。两种新的方法 openDrawer 和 closeDrawer 已经添加到 DrawerLayout
中,允许抽屉在没有动画的情况下打开或关闭。
您现在可以使用 openDrawer(drawerView, false)
和 closeDrawer(drawerView, false)
来无延迟地打开和关闭抽屉。
如果您在使用后退按钮返回到该实例的活动时,未调用
closeDrawer()
而直接调用
startActivity()
,则抽屉将保持打开状态。在调用
startActivity()
时调用
closeDrawer()
会出现一些问题,从卡顿的动画到长时间的感知延迟,具体取决于您使用的解决方法。因此,我认为最好的方法是只调用
startActivity()
,然后在返回时关闭抽屉。
为了使其正常工作,您需要一种在使用后退按钮导航回该活动时无需关闭动画即可关闭抽屉的方法。(一个相对浪费的解决方法是在导航回来时强制重新创建活动,但可以不这样做解决这个问题。)
您还需要确保仅在导航后返回时关闭抽屉,而不是在方向更改后关闭抽屉,但这很容易实现。
详情
(如果您只想查看代码,请跳过此解释。)
虽然从onCreate()
调用closeDrawer()
将使抽屉关闭,没有任何动画,但从onResume()
不是这样。从onResume()
调用closeDrawer()
会通过一个短暂可见的动画关闭抽屉。 DrawerLayout
不提供任何关闭抽屉而没有动画的方法,但可以扩展它以添加一个。
实际上,关闭抽屉只是将其滑出屏幕,因此您可以通过直接将抽屉移动到其“关闭”位置来有效地跳过动画。翻译方向将根据重力(左侧或右侧抽屉)而变化,确切位置取决于抽屉一旦布置了所有子项后的大小。
但仅仅移动它是不够的,因为DrawerLayout
在扩展的LayoutParams
中保留了一些内部状态,用于判断抽屉是否打开。如果您只是将抽屉移动到屏幕外,它将不知道它已关闭,这会引起其他问题。(例如,在下一个方向更改时,抽屉将重新出现。)
由于您正在将支持库编译到您的应用程序中,因此可以在android.support.v4.widget
包中创建一个类以访问其默认(软件包私有)部分,或扩展DrawerLayout
而不复制它需要的任何其他类。这也将减轻更新代码以适应支持库未来变化的负担。(尽可能地隔离您的代码与实现细节最好)。您可以使用moveDrawerToOffset()
来移动抽屉,并设置LayoutParams
以使其知道抽屉已关闭。
代码
这是跳过动画的代码:
// move drawer directly to the closed position
moveDrawerToOffset(drawerView, 0.f);
// set internal state so DrawerLayout knows it's closed
final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
lp.onScreen = 0.f;
lp.knownOpen = false;
invalidate();
注意:如果您只调用
moveDrawerToOffset()
而不更改
LayoutParams
,则抽屉将在下一次方向更改时移回其打开位置。
选项1(使用现有的DrawerLayout)
这种方法将一个实用类添加到support.v4包中,以便获取我们需要在DrawerLayout内部使用的package-private部分。
将这个类放入/src/android/support/v4/widget/目录下:
package android.support.v4.widget;
import android.support.annotation.IntDef;
import android.support.v4.view.GravityCompat;
import android.view.Gravity;
import android.view.View;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class Support4Widget {
@IntDef({Gravity.LEFT, Gravity.RIGHT, GravityCompat.START, GravityCompat.END})
@Retention(RetentionPolicy.SOURCE)
private @interface EdgeGravity {}
public static void setDrawerClosed(DrawerLayout drawerLayout, @EdgeGravity int gravity) {
final View drawerView = drawerLayout.findDrawerWithGravity(gravity);
if (drawerView == null) {
throw new IllegalArgumentException("No drawer view found with gravity " +
DrawerLayout.gravityToString(gravity));
}
drawerLayout.moveDrawerToOffset(drawerView, 0.f);
final DrawerLayout.LayoutParams lp = (DrawerLayout.LayoutParams) drawerView.getLayoutParams();
lp.onScreen = 0.f;
lp.knownOpen = false;
drawerLayout.invalidate();
}
}
在您离开页面时,在Activity中设置一个布尔值,表示应该关闭抽屉菜单:
public static final String CLOSE_NAV_DRAWER = "CLOSE_NAV_DRAWER";
private boolean mCloseNavDrawer;
@Override
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState != null) {
mCloseNavDrawer = savedInstanceState.getBoolean(CLOSE_NAV_DRAWER);
}
}
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
startActivity(intent);
mCloseNavDrawer = true;
}
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putBoolean(CLOSE_NAV_DRAWER, mCloseNavDrawer);
super.onSaveInstanceState(savedInstanceState);
}
在onResume()
中使用setDrawerClosed()
方法关闭抽屉,不带动画:
@Overrid6e
protected void onResume() {
super.onResume();
if(mCloseNavDrawer && mDrawerLayout != null && mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
Support4Widget.setDrawerClosed(mDrawerLayout, GravityCompat.START);
mCloseNavDrawer = false;
}
}
选项2(从DrawerLayout扩展)
这种方法是通过扩展DrawerLayout来添加setDrawerClosed()方法。
将此类放入/src/android/support/v4/widget/中:
package android.support.v4.widget;
import android.content.Context;
import android.support.annotation.IntDef;
import android.support.v4.view.GravityCompat;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class CustomDrawerLayout extends DrawerLayout {
@IntDef({Gravity.LEFT, Gravity.RIGHT, GravityCompat.START, GravityCompat.END})
@Retention(RetentionPolicy.SOURCE)
private @interface EdgeGravity {}
public CustomDrawerLayout(Context context) {
super(context);
}
public CustomDrawerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomDrawerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setDrawerClosed(View drawerView) {
if (!isDrawerView(drawerView)) {
throw new IllegalArgumentException("View " + drawerView + " is not a sliding drawer");
}
moveDrawerToOffset(drawerView, 0.f);
final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
lp.onScreen = 0.f;
lp.knownOpen = false;
invalidate();
}
public void setDrawerClosed(@EdgeGravity int gravity) {
final View drawerView = findDrawerWithGravity(gravity);
if (drawerView == null) {
throw new IllegalArgumentException("No drawer view found with gravity " +
gravityToString(gravity));
}
moveDrawerToOffset(drawerView, 0.f);
final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
lp.onScreen = 0.f;
lp.knownOpen = false;
invalidate();
}
}
在你的活动布局中使用 CustomDrawerLayout
替代 DrawerLayout
:
<android.support.v4.widget.CustomDrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
>
当您导航离开时,在您的活动中设置一个布尔值,指示抽屉应该被关闭:
public static final String CLOSE_NAV_DRAWER = "CLOSE_NAV_DRAWER";
private boolean mCloseNavDrawer;
@Override
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState != null) {
mCloseNavDrawer = savedInstanceState.getBoolean(CLOSE_NAV_DRAWER);
}
}
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
startActivity(intent);
mCloseNavDrawer = true;
}
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putBoolean(CLOSE_NAV_DRAWER, mCloseNavDrawer);
super.onSaveInstanceState(savedInstanceState);
}
在onResume()
中使用setDrawerClosed()
方法关闭抽屉,不带动画:
@Overrid6e
protected void onResume() {
super.onResume();
if(mCloseNavDrawer && mDrawerLayout != null && mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
mDrawerLayout.setDrawerClosed(GravityCompat.START);
mCloseNavDrawer = false;
}
}
isDrawerVisible
而不是isDrawerOpen
。记住,修改内容时需要保持原意,并使语言更加通俗易懂。 - Terel