Mostrar y ocultar una vista con una animación deslizante arriba / abajo

Tengo un LinearLayout que quiero mostrar u ocultar con una Animation que empuja el diseño hacia arriba o hacia abajo cada vez que cambio su visibilidad.

He visto algunas muestras pero ninguna de ellas satisface mis necesidades.

He creado dos archivos xml para las animaciones, pero no sé cómo iniciarlos cuando cambio la visibilidad de LinearLayout .

Con la nueva API de animación que se introdujo en Android 3.0 (Honeycomb) es muy simple crear tales animaciones.

Deslizando una View hacia abajo por una distancia:

 view.animate().translationY(distance); 

Luego puede volver a deslizar la View a su posición original de la siguiente manera:

 view.animate().translationY(0); 

También puede combinar fácilmente múltiples animaciones. La siguiente animación deslizará una View hacia abajo por su altura y la desvanecerá al mismo tiempo:

 // Prepare the View for the animation view.setVisibility(View.VISIBLE); view.setAlpha(0.0f); // Start the animation view.animate() .translationY(view.getHeight()) .alpha(1.0f) .setListener(null); 

Luego puede volver a fundir la View y deslizarla nuevamente a su posición original. También configuramos un AnimatorListener para que podamos volver a configurar la visibilidad de la View en GONE una vez que la animación haya finalizado:

 view.animate() .translationY(0) .alpha(0.0f) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); view.setVisibility(View.GONE); } }); 

Estaba teniendo problemas para entender y aplicar la respuesta aceptada. Necesitaba un poco más de contexto. Ahora que lo he descubierto, aquí hay un ejemplo completo:

enter image description here

MainActivity.java

 public class MainActivity extends AppCompatActivity { Button myButton; View myView; boolean isUp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myView = findViewById(R.id.my_view); myButton = findViewById(R.id.my_button); // initialize as invisible (could also do in xml) myView.setVisibility(View.INVISIBLE); myButton.setText("Slide up"); isUp = false; } // slide the view from below itself to the current position public void slideUp(View view){ view.setVisibility(View.VISIBLE); TranslateAnimation animate = new TranslateAnimation( 0, // fromXDelta 0, // toXDelta view.getHeight(), // fromYDelta 0); // toYDelta animate.setDuration(500); animate.setFillAfter(true); view.startAnimation(animate); } // slide the view from its current position to below itself public void slideDown(View view){ TranslateAnimation animate = new TranslateAnimation( 0, // fromXDelta 0, // toXDelta 0, // fromYDelta view.getHeight()); // toYDelta animate.setDuration(500); animate.setFillAfter(true); view.startAnimation(animate); } public void onSlideViewButtonClick(View view) { if (isUp) { slideDown(myView); myButton.setText("Slide up"); } else { slideUp(myView); myButton.setText("Slide down"); } isUp = !isUp; } } 

activity_mail.xml

       

Notas

  • Gracias a este artículo por señalarme en la dirección correcta. Fue más útil que las otras respuestas en esta página.
  • Si desea comenzar con la vista en la pantalla, no la inicialice como INVISIBLE .
  • Como lo estamos animando completamente fuera de la pantalla, no hay necesidad de volverlo a INVISIBLE . Sin embargo, si no está animando completamente fuera de la pantalla, puede agregar una animación alfa y establecer la visibilidad con AnimatorListenerAdapter .
  • Propiedad de documentos de animación

La solución más fácil: configure android:animateLayoutChanges="true" en el contenedor que contiene sus vistas.

Para ponerlo en contexto: si tiene un diseño como el que se muestra a continuación, todos los cambios de visibilidad en las vistas de este contenedor se animarán automáticamente.

    

Puede encontrar más detalles sobre esto en Animating Layout Changes – Android Developer

Puede iniciar la Animation correcta cuando la visibilidad de LinearLayout cambie al crear una nueva subclase de LinearLayout y reemplazar a setVisibility() para iniciar las Animations . Considera algo como esto:

 public class SimpleViewAnimator extends LinearLayout { private Animation inAnimation; private Animation outAnimation; public SimpleViewAnimator(Context context) { super(context); } public void setInAnimation(Animation inAnimation) { this.inAnimation = inAnimation; } public void setOutAnimation(Animation outAnimation) { this.outAnimation = outAnimation; } @Override public void setVisibility(int visibility) { if (getVisibility() != visibility) { if (visibility == VISIBLE) { if (inAnimation != null) startAnimation(inAnimation); } else if ((visibility == INVISIBLE) || (visibility == GONE)) { if (outAnimation != null) startAnimation(outAnimation); } } super.setVisibility(visibility); } } 
 if (filter_section.getVisibility() == View.GONE) { filter_section.animate() .translationY(filter_section.getHeight()).alpha(1.0f) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); filter_section.setVisibility(View.VISIBLE); filter_section.setAlpha(0.0f); } }); } else { filter_section.animate() .translationY(0).alpha(0.0f) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); filter_section.setVisibility(View.GONE); } }); } 

puede deslizar hacia arriba y hacia abajo cualquier vista o diseño mediante el uso del código de abajo en la aplicación de Android

 boolean isClicked=false; LinearLayout mLayoutTab = (LinearLayout)findViewById(R.id.linearlayout); if(isClicked){ isClicked = false; mLayoutTab.animate() .translationYBy(120) .translationY(0) .setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime)); }else{ isClicked = true; mLayoutTab.animate() .translationYBy(0) .translationY(120) .setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime)); } 

Use esta clase:

 public class ExpandCollapseExtention { public static void expand(View view) { view.setVisibility(View.VISIBLE); final int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); final int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); view.measure(widthSpec, heightSpec); ValueAnimator mAnimator = slideAnimator(view, 0, view.getMeasuredHeight()); mAnimator.start(); } public static void collapse(final View view) { int finalHeight = view.getHeight(); ValueAnimator mAnimator = slideAnimator(view, finalHeight, 0); mAnimator.addListener(new Animator.AnimatorListener() { @Override public void onAnimationEnd(Animator animator) { view.setVisibility(View.GONE); } @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); mAnimator.start(); } private static ValueAnimator slideAnimator(final View v, int start, int end) { ValueAnimator animator = ValueAnimator.ofInt(start, end); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { int value = (Integer) valueAnimator.getAnimatedValue(); ViewGroup.LayoutParams layoutParams = v.getLayoutParams(); layoutParams.height = value; v.setLayoutParams(layoutParams); } }); return animator; } } 

Aquí está mi solución. Solo haz una referencia a tu vista y llama a este método:

 public static void animateViewFromBottomToTop(final View view){ view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { view.getViewTreeObserver().removeOnGlobalLayoutListener(this); final int TRANSLATION_Y = view.getHeight(); view.setTranslationY(TRANSLATION_Y); view.setVisibility(View.GONE); view.animate() .translationYBy(-TRANSLATION_Y) .setDuration(500) .setStartDelay(200) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(final Animator animation) { view.setVisibility(View.VISIBLE); } }) .start(); } }); } 

No hay necesidad de hacer nada más =)

Tuve un caso de esquina donde la altura de mi vista todavía era zero así que …

 import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.view.View; public final class AnimationUtils { public static void slideDown(final View view) { view.animate() .translationY(view.getHeight()) .alpha(0.f) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { // superfluous restration view.setVisibility(View.GONE); view.setAlpha(1.f); view.setTranslationY(0.f); } }); } public static void slideUp(final View view) { view.setVisibility(View.VISIBLE); view.setAlpha(0.f); if (view.getHeight() > 0) { slideUpNow(view); } else { // wait till height is measured view.post(new Runnable() { @Override public void run() { slideUpNow(view); } }); } } private static void slideUpNow(final View view) { view.setTranslationY(view.getHeight()); view.animate() .translationY(0) .alpha(1.f) .setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { view.setVisibility(View.VISIBLE); view.setAlpha(1.f); } }); } }