An alternative to speeding up the animation and waiting for it to complete is a simple exception to the animation: just call startActivity() without calling closeDrawer() . Although you donβt see that the box is closed, the transition animation still provides a pretty nice effect, and this happens immediately, without having to wait until the animation closes the box to complete the setup first, without interruption and a shorter delay in perception.
More details
(You can skip this explanation if you just want to see the code.)
To do this, you will need a way to close the drawer without any close animation when you go to activity using the back button. (Without calling closeDrawer() , it will leave the box open in this instance of activity, with a relatively wasteful workaround, it will simply force the recreate() action when navigating backwards, but this can be solved without doing this.) You also need to make sure that you only close the drawer if you return after navigation, and not after changing orientation, but this is easy.
Although calling closeDrawer() from onCreate() will cause the box to close without any animation, the same does not apply to onResume() . Calling closeDrawer() from onResume() will close the box with the animation that instantly displays to the user. DrawerLayout provides no way to close a drawer without this animation, but you can add it.
As @syesilova notes, closing a drawer actually just shifts it off the screen. Thus, you can effectively skip the animation by moving the box directly to the "closed" position. The broadcast direction will change depending on gravity (whether it is the left or right drawer), and the exact position depends on the size of the drawer when it is laid out by all his children.
However, simply moving it is not enough, because DrawerLayout saves some internal state in the advanced LayoutParams , which it uses to find out if the box is open. If you simply move the box from the screen, it will not know that it is closed, and this will cause other problems. (For example, the box will reappear the next time the orientation changes.)
Since you are compiling the support library into your application, you can create a class in the android.support.v4.widget package to access its default parts (batch-private) or extend DrawerLayout without copying through any of the other classes in which it needs. It will also reduce the burden of updating code with future changes to the support library. (It is always best to isolate the code from the implementation details as much as possible.) You can use moveDrawerToOffset() to move the box and set LayoutParams so that it knows that the box is closed.
the code
This is the code that will skip the animation:
// move drawer directly to the closed position moveDrawerToOffset(drawerView, 0.f); // ...however, calling closeDrawer will set those LayoutParams // and invalidate the view. closeDrawer(drawerView);
Note: if you simply call moveDrawerToOffset() without changing LayoutParams , the box will return to the open position the next time you change the orientation.
Option 1 (use an existing DrawerLayout)
This approach adds a utility class to the support.v4 package to access the private parts of the package that we need inside DrawerLayout.
Put this class in / src / android / support / v 4 / 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)); }
Set a boolean in your activity when you move, indicating that the box should be closed:
public static final String CLOSE_NAV_DRAWER = "CLOSE_NAV_DRAWER"; private boolean mCloseNavDrawer; @Override public void onCreate(Bundle savedInstanceState) {
... and use the setDrawerClosed() method to close the box in onResume() without animation:
@Overrid6e protected void onResume() { super.onResume(); if(mCloseNavDrawer && mDrawerLayout != null && mDrawerLayout.isDrawerOpen(GravityCompat.START)) { Support4Widget.setDrawerClosed(mDrawerLayout, GravityCompat.START); mCloseNavDrawer = false; } }
Option 2 (extends from DrawerLayout)
This approach extends DrawerLayout to add the setDrawerClosed () method.
Put this class in / src / android / support / v 4 / 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"); }
Use CustomDrawerLayout instead of DrawerLayout in your action layouts:
<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" >
... and set a logical value in your activity when you move, indicating that the box should be closed:
public static final String CLOSE_NAV_DRAWER = "CLOSE_NAV_DRAWER"; private boolean mCloseNavDrawer; @Override public void onCreate(Bundle savedInstanceState) {
... and use the setDrawerClosed() method to close the box in onResume() without animation:
@Overrid6e protected void onResume() { super.onResume(); if(mCloseNavDrawer && mDrawerLayout != null && mDrawerLayout.isDrawerOpen(GravityCompat.START)) { mDrawerLayout.setDrawerClosed(GravityCompat.START); mCloseNavDrawer = false; } }
I found this to be the best way to avoid shaking without any long delayed delays.
You could use a similar technique to simulate closing a mailbox after activity has been reached, passing a value in the intention of telling new activity to open your mailbox without animation from onCreate() , and then revive it after the activity layout is complete, however, in my experiments, the activity transition destroyed the modeling effect , so you also need to disable it.