加快“导航抽屉”animationclosures的速度?

按照期望实现和工作,因此实际上没有任何值得在此发布的代码,只是想知道是否有人有加快抽屉打开和closures的时间的经验。 例如YouTube应用程序要快得多!

Solutions Collecting From Web of "加快“导航抽屉”animationclosures的速度?"

您肯定可以调整animation的持续时间,但是需要您从支持库中复制类,然后相应地进行编辑。

ViewDragHelper

持续时间在ViewDragHelper确定

然后当ViewDragHelper.smoothSlideViewTo被调用时被应用到DrawerLayout

您将需要创build一个ViewDragHelper.forceSettleCapturedViewAt的修改版本,它传递一个持续时间参数。

 forceSettleCapturedViewAt(... int duration) 

然后创build您的ViewDragHelper.smoothSlideViewTo版本。

 public boolean smoothSlideViewTo(... int duration) { ... return forceSettleCapturedViewAt(... int duration); } 

DrawerLayout

接下来,您需要修改DrawerLayout.closeDrawerDrawerLayout.closeDrawers以匹配您的新ViewDragHelper修改。

ActionBarDrawerToggle

你还必须复制ActionBarDrawerToggleActionBarDrawerToggleHoneycomb 。 这些文件不需要任何编辑。

加速animation并等待它完成的另一种方法是简单地避免animation:只需调用startActivity()而不调用closeDrawer() 。 尽pipe看不到抽屉,活动过渡animation仍然提供了相当不错的效果,并且它立即发生,不需要等待抽屉closuresanimation先完成定位,不会出现断断续续的情况,并且感知延迟更短。


细节

(如果你只是想看代码,你可以跳过这个解释。)

为了使这个工作,你需要一种方式来closures抽屉时没有任何closures的animation,当返回到后退button的活动。 (不调用closeDrawer()将使抽屉在该活动实例中处于打开状态;相对浪费的解决方法是在导航返回时强制recreate() ,但可以在不这样做的情况下解决此问题)。如果您在导航之后回来,而不是在方向改变之后,确保您只closures抽屉,但这很容易。

尽pipe从onCreate()调用closeDrawer()会使抽屉在没有任何animation的情况下开始closures,但onResume()并不是这样。 从onResume()调用closeDrawer()将closures抽屉,这个animation对用户来说是瞬间可见的。 DrawerLayout不提供任何方法来closures没有该animation的抽屉,但是可以添加一个。

正如@syesilova所指出的那样,closures抽屉实际上就是把它从屏幕上滑下来。 因此,您可以通过将抽屉直接移动到“closures”位置来有效地跳过animation。 翻译的方向会根据重力(无论是左边还是右边的抽屉)而有所不同,确切的位置取决于抽屉与所有孩子一起布置的大小。

然而,简单地移动它还不够,因为DrawerLayout在扩展的LayoutParams中保持一些内部状态,用来确定抽屉是否打开。 如果您只是将抽屉移出屏幕,则不会知道它已closures,这会导致其他问题。 (例如,抽屉将在下一个方向更改上重新出现。)

由于您正在将支持库编译到应用程序中,因此您可以在android.support.v4.widget包中创build一个类,以访问其默认(包私有)部分,或者扩展DrawerLayout而不复制其他任何其他它需要的类。 这也将减less未来更改支持库时更新代码的负担。 (最好尽可能地将代码与实现细节隔离。)您可以使用moveDrawerToOffset()移动抽屉,并设置LayoutParams以便知道抽屉已closures。


这是跳过animation的代码:

 // move drawer directly to the closed position moveDrawerToOffset(drawerView, 0.f); /* EDIT: as of v23.2.1 this direct approach no longer works because the LayoutParam fields have been made private... // set internal state so DrawerLayout knows it's closed final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams(); lp.onScreen = 0.f; lp.knownOpen = false; invalidate(); /*/ // ...however, calling closeDrawer will set those LayoutParams // and invalidate the view. closeDrawer(drawerView); /**/ 

注意:如果您只是在不更改LayoutParams情况下调用moveDrawerToOffset() ,则在下一个方向更改时,抽屉将移回其打开位置。


选项1(使用现有的DrawerLayout)

这种方法在support.v4包中添加了一个实用程序类,以访问我们在DrawerLayout中需要的包 – 私有部分。

把这个类放到/ 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 { /** @hide */ @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)); } // move drawer directly to the closed position drawerLayout.moveDrawerToOffset(drawerView, 0.f); /* EDIT: as of v23.2.1 this no longer works because the LayoutParam fields have been made private, but calling closeDrawer will achieve the same result. // set internal state so DrawerLayout knows it's closed final DrawerLayout.LayoutParams lp = (DrawerLayout.LayoutParams) drawerView.getLayoutParams(); lp.onScreen = 0.f; lp.knownOpen = false; drawerLayout.invalidate(); /*/ // Calling closeDrawer updates the internal state so DrawerLayout knows it's closed // and invalidates the view for us. drawerLayout.closeDrawer(drawerView); /**/ } } 

当您离开时,在您的活动中设置一个布尔值,表明抽屉应该closures:

 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); } 

…并使用setDrawerClosed()方法closures没有animation的onResume()的抽屉:

 @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 { /** @hide */ @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"); } // move drawer directly to the closed position moveDrawerToOffset(drawerView, 0.f); /* EDIT: as of v23.2.1 this no longer works because the LayoutParam fields have been made private, but calling closeDrawer will achieve the same result. // set internal state so DrawerLayout knows it's closed final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams(); lp.onScreen = 0.f; lp.knownOpen = false; invalidate(); /*/ // Calling closeDrawer updates the internal state so DrawerLayout knows it's closed // and invalidates the view for us. closeDrawer(drawerView); /**/ } 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)); } // move drawer directly to the closed position moveDrawerToOffset(drawerView, 0.f); /* EDIT: as of v23.2.1 this no longer works because the LayoutParam fields have been made private, but calling closeDrawer will achieve the same result. // set internal state so DrawerLayout knows it's closed final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams(); lp.onScreen = 0.f; lp.knownOpen = false; invalidate(); /*/ // Calling closeDrawer updates the internal state so DrawerLayout knows it's closed // and invalidates the view for us. closeDrawer(drawerView); /**/ } } 

在您的活动布局中使用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" > 

…当您离开时,在您的活动中设置一个布尔值,指示抽屉应该closures:

 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); } 

…并使用setDrawerClosed()方法closures没有animation的onResume()的抽屉:

 @Overrid6e protected void onResume() { super.onResume(); if(mCloseNavDrawer && mDrawerLayout != null && mDrawerLayout.isDrawerOpen(GravityCompat.START)) { mDrawerLayout.setDrawerClosed(GravityCompat.START); mCloseNavDrawer = false; } } 

我发现这是避免长时间感知延迟的最好办法。

几乎可以使用类似的技术来模拟在到达一个活动后closures抽屉,通过传递一个值来告诉新的活动在onCreate()没有animation的情况下打开它的抽屉,然后在活动的布局之后closures它的animation完成了,但是在我的实验中,活动转换破坏了模拟的效果,所以你还需要禁用它。

首先从下面链接下载sourcode文件

DrawerLayout.java

ViewDrawerHelper.java

并将上述两个文件粘贴到应用程序util包中(或者你想要的位置),并在你的activity中引用这个抽屉布局而不是android.support.v4.widget.DrawerLayout在activity的布局文件中改变抽屉布局的引用,

现在调整

 private static final int MAX_SETTLE_DURATION = 600; // ms 

ViewDrawerHelper,加快只是增加值,减less只是减less的价值。

如果你想添加动作栏上的切换button,然后从下面的链接下载的源文件

ActionBarDrawerToggle.java

ActionBarDrawerToggleJellybeanMR2.java

ActionBarDrawerToggleHoneycomb.java

并将上述文件粘贴到您的应用程序util包中(或者您想要的位置)注意: – 确保每个新添加的文件的导入包引用的是您的应用程序项目中的文件,而不是android.support.v4.widget。 *;

如果上述链接不工作,请添加http://

如果你想强制立即消失,没有任何animation的左侧面板,你可以简单地设置它的x值。 抽屉布局打开时,其左侧面板的x值变为0,closures时变为-1 *(其宽度)。 所以如果在打开时设置x值-2 *宽度,则左面板立即消失。 当然,不要忘了在closures之后将x设置为-1 *宽度。 例如:

 DisplayMetrics metrics = new DisplayMetrics(); this.getWindowManager().getDefaultDisplay().getMetrics(metrics); //obtain left panel's width in px private float mToggleStartX=-260*metrics.density; //260 is the width of left panel in dpi //while drawer layout is opened, to disappear left panel ll_drawerLayoutMenuPanel.setX(mToggleStartX*2); //ll_drawerLayoutMenuPanel is the left panel layout mDrawerLayout.closeDrawers(); //don't forget reset x value in the onDrawerClosed method. mDrawerToggle = new ActionBarDrawerToggle(this,mDrawerLayout,mainToolBar,R.string.drawer_open,R.string.drawer_close) { public void onDrawerClosed(View view) { super.onDrawerClosed(view); ll_drawerLayoutMenuPanel.setX(mToggleStartX); } ...... }; 

这不允许你改变animation的速度,但是如果你只想要立即closures一个抽屉,你可以在支持库的DrawerLayout.closeDrawer(int/View, bool)使用新的DrawerLayout.closeDrawer(int/View, bool)方法:

 drawerLayout.closeDrawer(Gravity.LEFT, false); 

我相信你的问题的真正含义是我怎样才能让animation运行更顺利,我点击菜单drawerlayout开始新的活动。
如果这是你问题的意思,那我就是这么做的。

 mLeftDrawer.ItemClick += delegate (object sender, Android.Widget.AdapterView.ItemClickEventArgs e) { // Mark that item is selected and ask redraw e.View.Selected = true; adapter.NotifyDataSetChanged(); var handler = new Handler(); handler.PostDelayed(new Java.Lang.Runnable(() => { _mLeftDrawerLayout.CloseDrawers(); // Here you should call your activity }), 100); };