¿Acelerar la velocidad de animación de “Cajón de navegación” al cerrar?

Implementado y funcionando como se esperaba, como tal, realmente no hay un código que valga la pena publicar aquí, simplemente buscando saber si alguien tiene experiencia en acelerar el tiempo que tarda el cajón en abrirse y cerrarse. ¡La aplicación de YouTube, por ejemplo, es mucho más rápida!

Definitivamente puede ajustar la duración de la animación, pero requerirá que copie las clases de la biblioteca de soporte, y luego las edite en consecuencia.

ViewDragHelper

La duración se determina aquí en ViewDragHelper

Luego se aplica a DrawerLayout cuando se llama a ViewDragHelper.smoothSlideViewTo

Deberá crear una versión modificada de ViewDragHelper.forceSettleCapturedViewAt que pase en un ViewDragHelper.forceSettleCapturedViewAt duración.

 forceSettleCapturedViewAt(... int duration) 

Luego crea tu versión de ViewDragHelper.smoothSlideViewTo .

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

DrawerLayout

A continuación, deberá modificar DrawerLayout.closeDrawer y DrawerLayout.closeDrawers para que coincidan con sus nuevas modificaciones de ViewDragHelper .

ActionBarDrawerToggle

También deberá copiar sobre ActionBarDrawerToggle y ActionBarDrawerToggleHoneycomb . Sin embargo, estos archivos no requerirán ninguna edición.

Una alternativa para acelerar la animación y esperar que termine es simplemente evitar la animación en primer lugar: simplemente llame a startActivity() sin llamar a closeDrawer() . Aunque no ve el cajón cerca, la animación de transición de actividad todavía proporciona un efecto bastante agradable, y se produce inmediatamente, sin necesidad de esperar a que la animación de cierre del cajón termine de establecerse primero, sin interrupciones y un retraso perceptual mucho más corto. .


Detalles

(Puede omitir esta explicación si solo quiere ver el código).

Para que esto funcione, necesita una forma de cerrar el cajón sin ninguna animación cercana cuando navegue de regreso a la actividad con el botón Atrás. (No llamar a closeDrawer() dejará el cajón abierto en esa instancia de actividad, una solución relativamente derrochadora sería simplemente forzar a la actividad a recreate() cuando navegue hacia atrás, pero es posible resolver esto sin hacerlo.) También necesita asegúrese de cerrar el cajón solo si regresa después de navegar, y no después de un cambio de orientación, pero eso es fácil.

Aunque llamar a closeDrawer() desde onCreate() hará que el cajón se cierre sin ninguna animación, lo mismo no es cierto desde onResume() . Al llamar a closeDrawer() desde onResume() se cerrará el cajón con una animación momentáneamente visible para el usuario. DrawerLayout no proporciona ningún método para cerrar el cajón sin esa animación, pero es posible agregar uno.

Como señala @syesilova, cerrar el cajón en realidad simplemente lo desliza fuera de la pantalla. De modo que puede omitir la animación al mover el cajón directamente a su posición “cerrada”. La dirección de traslación variará de acuerdo con la gravedad (ya sea un cajón izquierdo o derecho) y la posición exacta dependerá del tamaño del cajón una vez que esté distribuido con todos sus elementos secundarios.

Sin embargo, simplemente moverlo no es suficiente, ya que DrawerLayout mantiene algún estado interno en los LayoutParams ampliados que usa para saber si el cajón está abierto. Si solo mueve el cajón de la pantalla, no sabrá que está cerrado, y eso causará otros problemas. (Por ejemplo, el cajón volverá a aparecer en el próximo cambio de orientación).

Como está comstackndo la biblioteca de soporte en su aplicación, puede crear una clase en el paquete android.support.v4.widget para obtener acceso a sus partes predeterminadas (paquete-privado), o extender DrawerLayout sin copiar sobre ninguna de las otras clases que necesita Esto también reducirá la carga de actualizar su código con cambios futuros en la biblioteca de soporte. (Siempre es mejor aislar su código de los detalles de implementación tanto como sea posible). Puede usar moveDrawerToOffset() para mover el cajón y establecer los LayoutParams para que sepa que el cajón está cerrado.


Código

Este es el código que omitirá la animación:

 // 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); /**/ 

Nota: si solo llama a moveDrawerToOffset() sin cambiar los LayoutParams , el cajón volverá a su posición abierta en el siguiente cambio de orientación.


Opción 1 (usar DrawerLayout existente)

Este enfoque agrega una clase de utilidad al paquete support.v4 para obtener acceso a las partes privadas del paquete que necesitamos dentro de DrawerLayout.

Coloque esta clase en / 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); /**/ } } 

Establezca un booleano en su actividad cuando se vaya, indicando que el cajón debe estar cerrado:

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

… y use el método setDrawerClosed() para cerrar el cajón en onResume() sin animación:

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

Opción 2 (extender desde DrawerLayout)

Este enfoque extiende DrawerLayout para agregar un método setDrawerClosed ().

Coloque esta clase en / 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); /**/ } } 

Use CustomDrawerLayout lugar de DrawerLayout en sus diseños de actividades:

  

… y establezca un booleano en su actividad cuando se vaya, indicando que el cajón debe estar cerrado:

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

… y use el método setDrawerClosed() para cerrar el cajón en onResume() sin animación:

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

Encontré esta la mejor manera de evitar los cortes sin largas demoras perceptivas.

Casi podría usar una técnica similar para simular cerrar el cajón después de llegar a una actividad, pasando un valor con la intención de decirle a la nueva actividad que abra su cajón sin animación desde onCreate() y luego animarlo cerrado después del diseño de la actividad finaliza, sin embargo, en mis experimentos, la transición de actividad arruinó el efecto de la simulación, por lo que también necesitaría desactivarlo.

Primero desde los enlaces inferiores descarga los archivos sourcode

DrawerLayout.java

Y

ViewDrawerHelper.java

y pegue los dos archivos anteriores en su paquete utilidades de aplicaciones (o donde desee) y tome como referencia el diseño de esta gaveta en su actividad no de android.support.v4.widget.DrawerLayout cambie la referencia de diseño de la gaveta en el archivo de diseño de la actividad,

Ahora ajusta

 private static final int MAX_SETTLE_DURATION = 600; // ms 

de ViewDrawerHelper, para acelerar, simplemente aumente el valor y, para disminuir, disminuya el valor.

Si desea agregar acción al botón para activar la barra de acciones, a continuación, desde los enlaces a continuación, descargue los archivos fuente de

ActionBarDrawerToggle.java

ActionBarDrawerToggleJellybeanMR2.java

ActionBarDrawerToggleHoneycomb.java

y pegue los archivos anteriores en su paquete utilidades de aplicaciones (o donde desee) Nota: – Asegúrese de que los paquetes importados de cada archivo agregado recientemente se refieran al archivo que está en su proyecto de aplicación, no de android.support.v4.widget. *;

si los enlaces anteriores no funcionan, agregue http: //

Si desea forzar a desaparecer inmediatamente el panel izquierdo sin ninguna animación, simplemente puede establecer su valor de x. Cuando se abre el diseño del cajón, el valor x de su panel izquierdo se convierte en 0, y cuando se cierra se convierte en -1 * (su ancho). Entonces, si configura x valor -2 * ancho mientras está abierto, el panel izquierdo desaparece inmediatamente. Y por supuesto, no te olvides de configurar x a -1 * de ancho después de que se cierre. Por ejemplo:

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

Esto no le permite cambiar la velocidad de animación, pero si todo lo que quiere es cerrar instantáneamente un cajón, puede usar los nuevos DrawerLayout.closeDrawer(int/View, bool) en la v24 de la biblioteca de soporte:

 drawerLayout.closeDrawer(Gravity.LEFT, false); 

Creo que el verdadero significado de su pregunta es cómo puedo hacer que la animación se ejecute más suavemente después de hacer clic en el menú en drawerlayout que inicia la nueva actividad.
Si este es el significado de su pregunta, así es como lo hago.

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

Cierre el cajón después de un retraso según el siguiente

 @Override public boolean onNavigationItemSelected(MenuItem item) { // Handle navigation view item clicks here. yourFunction(); Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { drawer.closeDrawer(GravityCompat.START); } }, 100); return true; }