我可以通过编程以动画的方式打开抽屉布局吗?

21
3个回答

53

预绘制监听器,也称为安全方式

这是一个预绘制监听器的示例。它会尽可能快地启动动画,可能会有点太快。您可能需要将其与第二个可运行对象组合使用。我不会展示两者的组合,仅单独展示。

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    // Building NavDrawer logic here. Just a method call would be best.
    ...

    ViewTreeObserver vto = drawer.getViewTreeObserver();
    if (vto != null) vto.addOnPreDrawListener(new ShouldShowListener(drawer));
}

private static class ShouldShowListener implements OnPreDrawListener {

    private final DrawerLayout drawerLayout;

    private ShouldShowListener(DrawerLayout drawerLayout) {
        this.drawerLayout= drawerLayout;
    }

    @Override
    public boolean onPreDraw() {
        if (view != null) {
            ViewTreeObserver vto = view.getViewTreeObserver();
            if (vto != null) {
                vto.removeOnPreDrawListener(this);
            }
        }

        drawerLayout.openDrawer(Gravity.LEFT);
        return true;
    }
}

PostDelay Runnable,又称危险生活

// Delay is in milliseconds
static final int DRAWER_DELAY = 200;

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    // Building NavDrawer logic here. Just a method call would be best.
    ...
    new Handler().postDelayed(openDrawerRunnable(), DRAWER_DELAY);
}

private Runnable openDrawerRunnable() {
    return new Runnable() {

        @Override
        public void run() {
            drawerLayout.openDrawer(Gravity.LEFT);
        }
    }
}

警告

如果在应用程序首次启动时它们开始旋转,糟糕了! 阅读此博客文章以获取更多信息:http://corner.squareup.com/2013/12/android-main-thread-2.html。最好的做法是使用predraw监听器或在onPause中删除您的可运行项。


1
如果在所有情况下200毫秒不够用怎么办? - Zordid
然后将其制作成您需要的任何长度。 - MinceMan
1
这不是我想要的意思。这种方法不好 - 每当准备时间超出预期,它就会失败。正如你所说的,“祝你好运”确实很合适... :-) - Zordid
我明白你的意思,但我认为如果在onCreate之后花费超过200或300毫秒来构建抽屉和活动,则表示你正在做一些错误的事情。 - MinceMan
没错。没有问题。比如旧设备 - HTC Hero。或者是在我的开发机上的模拟器。在这种情况下,这根本不起作用。你需要在 Activity 绘制时精确地触发抽屉的打开。为此,请将 onPreDrawListener 放到 ViewTreeObserver 中 - 这总是比依赖固定时间更好! - Zordid
显示剩余2条评论

7
您可以在DrawerLayout上调用openDrawer(int gravity)以使其动画打开抽屉。

我在Fragment Activity的onStart()方法中调用它,抽屉没有动画显示。我是在错误的位置调用还是参数应该放什么重力值? - benleung
如果通常情况下它从应用程序的左侧出现,请使用Gravity.LEFT。看看是否有帮助。否则,尝试在片段生命周期的稍后调用它,例如onResume。 - Brayden
如果我在onResume()中调用它,那么这意味着即使进行多任务切换,抽屉也会打开吗? - benleung
我也在寻找解决方案。从onResume()调用时它也不会执行动画。文档中似乎还有一个错别字。在一个版本的openDrawer中,它说“...使其动画退出视图”,而在另一个版本中则说“...使其动画进入视图”。 - joepetrakovich
3
您可以尝试使用postDelayed(Runnable, long)方法延迟一段时间来执行操作。这样,直到界面稳定后才会打开它。 - ariets
...但前提是您选择的延迟值足够。如果您问我,这不是一个好方法,如果设备真的很慢或正在执行许多任务,它可能会出现故障。 - Zordid

2

您需要调用 drawerLayout.openDrawer(Gravity.LEFT) 来启动抽屉的动画效果。如果您在 Activity 生命周期过早地进行此调用,抽屉将无法进行动画。

最简单的解决方案是在 onCreate() 中设置一个标志,并在 onResume() 中执行操作。

确保仅在 savedInstanceState 为 null 时设置标志,说明 Activity 不是从后台恢复的。您不希望每次更改方向或切换应用程序时都会滑出抽屉。

public class MainActivity extends ActionBarActivity {
    private DrawerLayout drawerLayout;
    private boolean firstResume = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        drawerLayout = (DrawerLayout)findViewById(R.id.drawer);

        if(savedInstanceState == null){
            firstResume = true;
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        if(firstResume) {
            drawerLayout.openDrawer(Gravity.LEFT);
        }

        firstResume = false;
    }
}

你还可以使用一个 OnPreDrawListener,但我觉得这样做有点过于复杂了,因为 onPreDraw 会被多次调用,所以你需要在打开抽屉后移除监听器。而且,你也假定 preDraw 是激活抽屉的合适时间,这是抽屉布局的内部实现。例如,在 onDraw 之后才能正确地执行动画的未来实现可能不会很好。

将抽屉延迟几毫秒再打开是解决此问题的危险方法。在最坏的情况下,如果用户快速导航,那么打开抽屉的调用可能会发生在 onDestroy 之后。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接