Android agrega animaciones simples mientras establece la visibilidad (view.Gone)

237

He diseñado un diseño simple. He terminado el diseño sin animación, pero ahora quiero agregar animaciones cuando haga clic en el evento de vista de texto y no sé cómo usarlo. ¿Mi diseño xml se ve bien o no? Cualquier sugerencia sera apreciada.

Mi XML

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:longClickable="false"
    android:orientation="vertical"
    android:weightSum="16" >

<LinearLayout 
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#00DDA0"
    android:layout_weight="3" >
</LinearLayout>
 <TextView
        android:id="@+id/Information1"
        android:layout_width="match_parent"
        android:layout_height="1dp" 
        android:text="Child Information" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>

 <LinearLayout
     android:id="@+id/layout1"
     android:layout_width="fill_parent"
     android:layout_height="0dp"
     android:layout_weight="8.5"
     android:background="#BBBBBB"
     android:orientation="vertical" >

     <TextView
         android:id="@+id/textView1"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" />
 </LinearLayout>

  <TextView
        android:id="@+id/Information2"
        android:layout_width="match_parent"
        android:layout_height="0dp" 
        android:text="Parent Information" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>
  <LinearLayout 
          android:id="@+id/layout2"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#BBBBBB"
    android:layout_weight="8.5" >
     <TextView
         android:id="@+id/textView2"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" />
      </LinearLayout>
   <TextView
        android:id="@+id/Information3"
        android:layout_width="match_parent"
        android:layout_height="0dp" 
        android:text="Siblings" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>
   <LinearLayout 
          android:id="@+id/layout3"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#BBBBBB"
    android:layout_weight="8.5" >
     <TextView
         android:id="@+id/textView3"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" />
      </LinearLayout>
    <TextView
        android:id="@+id/Information4"
        android:layout_width="match_parent"
        android:layout_height="0dp" 
        android:text="Teacher Information" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>
    <LinearLayout 
          android:id="@+id/layout4"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#BBBBBB"
    android:layout_weight="8.5" >
     <TextView
         android:id="@+id/textView4"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" />
      </LinearLayout>
     <TextView
        android:id="@+id/Information5"
        android:layout_width="match_parent"
        android:layout_height="0dp" 
        android:text="Grade Information" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>
     <LinearLayout 
          android:id="@+id/layout5"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#BBBBBB"
    android:layout_weight="8.5" >
     <TextView
         android:id="@+id/textView5"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" />
      </LinearLayout>
      <TextView
        android:id="@+id/Information6"
        android:layout_width="match_parent"
        android:layout_height="0dp" 
        android:text="Health Information" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>
      <LinearLayout 
          android:id="@+id/layout6"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#BBBBBB"
    android:layout_weight="8.5" >
    <TextView
         android:id="@+id/textView5"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" 
         android:layout_weight="8.5" />
      </LinearLayout>

</LinearLayout>

Mi java

public class Certify_Info extends Activity {

    private static TextView tv2,tv3,tv5,tv6,tv4,tv1;
    private static LinearLayout l1,l2,l3,l4,l5,l6;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_certify__info);

        tv1=(TextView) findViewById(R.id.Information1);
        tv2=(TextView) findViewById(R.id.Information2);
        tv3=(TextView) findViewById(R.id.Information3);
        tv4=(TextView) findViewById(R.id.Information4);
        tv5=(TextView) findViewById(R.id.Information5);
        tv6=(TextView) findViewById(R.id.Information6); 

        l1=(LinearLayout) findViewById(R.id.layout1);
        l2=(LinearLayout) findViewById(R.id.layout2);
        l3=(LinearLayout) findViewById(R.id.layout3);
        l4=(LinearLayout) findViewById(R.id.layout4);
        l5=(LinearLayout) findViewById(R.id.layout5);
        l6=(LinearLayout) findViewById(R.id.layout6); 

        l2.setVisibility(View.GONE);
        l3.setVisibility(View.GONE); 
        l4.setVisibility(View.GONE); 
        l5.setVisibility(View.GONE);
        l6.setVisibility(View.GONE);

        tv1.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l2.setVisibility(View.GONE);
                l3.setVisibility(View.GONE); 
                l4.setVisibility(View.GONE); 
                l5.setVisibility(View.GONE);
                l6.setVisibility(View.GONE);
                l1.setVisibility(View.VISIBLE);
            }
        });
        tv2.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l1.setVisibility(View.GONE);
                l3.setVisibility(View.GONE); 
                l4.setVisibility(View.GONE); 
                l5.setVisibility(View.GONE);
                l6.setVisibility(View.GONE);
                l2.setVisibility(View.VISIBLE);
            }
        });
        tv3.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l1.setVisibility(View.GONE);
                l2.setVisibility(View.GONE);
                l4.setVisibility(View.GONE); 
                l5.setVisibility(View.GONE);
                l6.setVisibility(View.GONE);
                l3.setVisibility(View.VISIBLE);

            }
        });
        tv4.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l1.setVisibility(View.GONE);
                l2.setVisibility(View.GONE);
                l3.setVisibility(View.GONE); 
                l4.setVisibility(View.GONE); 
                l5.setVisibility(View.GONE);
                l6.setVisibility(View.GONE);
                l4.setVisibility(View.VISIBLE); 
            }
        });
        tv5.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l1.setVisibility(View.GONE);
                l2.setVisibility(View.GONE);
                l3.setVisibility(View.GONE); 
                l4.setVisibility(View.GONE); 
                l6.setVisibility(View.GONE);
                l5.setVisibility(View.VISIBLE); 
            }
        });
        tv6.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l1.setVisibility(View.GONE);
                l2.setVisibility(View.GONE);
                l3.setVisibility(View.GONE); 
                l4.setVisibility(View.GONE); 
                l5.setVisibility(View.GONE);
                l6.setVisibility(View.VISIBLE);
            }
        });

    }
}
arun
fuente

Respuestas:

706

Puede hacer dos cosas para agregar animaciones, primero puede dejar que Android anime los cambios de diseño por usted. De esa manera, cada vez que cambie algo en el diseño, como cambiar la visibilidad de la vista o las posiciones de la vista, Android creará automáticamente animaciones de transición / transición. Para usar ese conjunto

android:animateLayoutChanges="true"

en el nodo raíz en su diseño.

Su segunda opción sería agregar animaciones manualmente. Para esto le sugiero que use la nueva API de animación introducida en Android 3.0 (Honeycomb). Te puedo dar algunos ejemplos:

Esto se desvanece a View:

view.animate().alpha(0.0f);

Esto se desvanece de nuevo en:

view.animate().alpha(1.0f);

Esto mueve Viewhacia abajo por su altura:

view.animate().translationY(view.getHeight());

Esto devuelve el Viewa su posición inicial después de que se haya movido a otro lugar:

view.animate().translationY(0);

También puede usar setDuration()para establecer la duración de la animación. Por ejemplo, esto se desvanece Viewen un período de 2 segundos:

view.animate().alpha(0.0f).setDuration(2000);

Y puede combinar tantas animaciones como desee, por ejemplo, esto se desvanece View y lo mueve hacia abajo al mismo tiempo durante un período de 0.3 segundos:

view.animate()
        .translationY(view.getHeight())
        .alpha(0.0f)
        .setDuration(300);

Y también puede asignar un oyente a la animación y reaccionar a todo tipo de eventos. Como cuando comienza la animación, cuando termina o se repite, etc. Al usar la clase abstracta AnimatorListenerAdapter, no tiene que implementar todas las devoluciones de llamada de AnimatorListeneruna sola vez, sino solo las que necesita. Esto hace que el código sea más legible. Por ejemplo, el siguiente código se desvanece y lo Viewmueve hacia abajo por su altura durante un período de 0.3 segundos (300 milisegundos) y cuando se completa la animación, su visibilidad se establece en View.GONE.

view.animate()
        .translationY(view.getHeight())
        .alpha(0.0f)
        .setDuration(300)
        .setListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                view.setVisibility(View.GONE);
            }
        });
Xaver Kapeller
fuente
66
@ Natix No llamaría redundante a esa súper llamada. No hagas ediciones superficiales de que no hay nada malo.
Xaver Kapeller
55
Es bueno pero el inverso no funciona correctamente ¿por qué? view.setVisibility (View.VISIBLE); CON alfa (1.0f), aparece con 100 relleno superior ...
entrega
15
Debe borrar la animación antes de establecer la visibilidad >> de lo view.clearAnimation(); view.setVisibility(View.GONE);contrario, el diseño permanecerá invisible y no desaparecerá.
Eftekhari
2
@Eftekhari No requieren muchos recursos. Y si tiene una versión de Android actualizada, pero aún experimenta un retraso que probablemente tenga un teléfono antiguo con poca memoria o un chip de gráficos incorrecto. Y no estoy hablando de una nueva biblioteca. Los animadores son nativos. Son parte del Marco de Android. Se lanzaron hace 5 años y hoy el 97.9% de todos los dispositivos los admiten. No hay ninguna razón para no usar Animators o al menos ViewCompat.animate()que es parte de la biblioteca de soporte y usa Animators en versiones más nuevas y View Animations en Android 3.0 y versiones posteriores.
Xaver Kapeller
1
Pero cuando el 97.9% de todos los dispositivos son Android 4.0 y superiores, no queda mucho caso de uso ViewCompat.animate().
Xaver Kapeller
70

La forma más fácil de animar Visibilitycambios es usar el Transition APIpaquete de soporte disponible (androidx). Simplemente llame al TransitionManager.beginDelayedTransitionmétodo y luego cambie la visibilidad de la vista. Hay varias transiciones predeterminadas como Fade, Slide.

import androidx.transition.TransitionManager;
import androidx.transition.Transition;
import androidx.transition.Fade;

private void toggle() {
    Transition transition = new Fade();
    transition.setDuration(600);
    transition.addTarget(R.id.image);

    TransitionManager.beginDelayedTransition(parent, transition);
    image.setVisibility(show ? View.VISIBLE : View.GONE);
}

¿Dónde parentestá el padre ViewGroupde la vista animada? Resultado:

ingrese la descripción de la imagen aquí

Aquí está el resultado con la Slidetransición:

import androidx.transition.Slide;

Transition transition = new Slide(Gravity.BOTTOM);

ingrese la descripción de la imagen aquí

Es fácil escribir una transición personalizada si necesita algo diferente. Aquí hay un ejemplo con el CircularRevealTransitionque escribí en otra respuesta . Muestra y oculta la vista con la animación CircularReveal.

Transition transition = new CircularRevealTransition();

ingrese la descripción de la imagen aquí

android:animateLayoutChanges="true"La opción hace lo mismo, solo usa AutoTransition como transición.

ashakirov
fuente
@TouhidulIslam no. Estas clases están disponibles en el paquete androidx. Todo es compatible con versiones anteriores
ashakirov
2
¿Qué pasa con expandir / contraer un grupo de vistas?
TheRealChx101
¿Puedes hacer múltiples beginDelayedTransitions?
Jeongbebs
26

Por favor revisa esto enlace. Lo que permitirá animaciones como L2R, R2L, T2B, B2T.

Este código muestra animación de izquierda a derecha

TranslateAnimation animate = new TranslateAnimation(0,view.getWidth(),0,0);
animate.setDuration(500);
animate.setFillAfter(true);
view.startAnimation(animate);
view.setVisibility(View.GONE);

si quieres hacerlo desde R2L, usa

TranslateAnimation animate = new TranslateAnimation(0,-view.getWidth(),0,0);

de arriba a abajo como

TranslateAnimation animate = new TranslateAnimation(0,0,0,view.getHeight());

y viceversa ...

Excepción de puntero nulo
fuente
8
Esto desplaza la vista desde su posición original.
Relm
24

Intente agregar esta línea al diseño padre xml

 android:animateLayoutChanges="true"

Su diseño se verá así

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:animateLayoutChanges="true"
    android:longClickable="false"
    android:orientation="vertical"
    android:weightSum="16">

    .......other code here

    </LinearLayout>
Ricardo Romo
fuente
Esto funcionó para mí. Mi configuración utiliza un diseño de restricción como vista raíz. Cuando la vista se establece en View.VISIBLE, se muestra la animación
EdgeDev
solución muy simple y elegante
Naveed Ahmad
11

Basado en la respuesta de @Xaver Kapeller, descubrí una forma de crear animación de desplazamiento cuando aparecen nuevas vistas en la pantalla (y también animación para ocultarlas).

Va de este estado:

  • Botón
  • Último botón

a

  • Botón
  • Botón 1
  • Botón 2
  • Botón 3
  • Botón 4
  • Último botón

y viceversa.

Entonces, cuando el usuario hace clic en el primer botón, los elementos "Botón 1", "Botón 2", "Botón 3" y "Botón 4" aparecerán usando animación de desvanecimiento y el elemento "Último botón" se moverá hacia abajo hasta el final. La altura del diseño también cambiará, lo que permite usar la vista de desplazamiento correctamente.

Este es el código para mostrar elementos con animación:

private void showElements() {
    // Precondition
    if (areElementsVisible()) {
        Log.w(TAG, "The view is already visible. Nothing to do here");
        return;
    }

    // Animate the hidden linear layout as visible and set
    // the alpha as 0.0. Otherwise the animation won't be shown
    mHiddenLinearLayout.setVisibility(View.VISIBLE);
    mHiddenLinearLayout.setAlpha(0.0f);
    mHiddenLinearLayout
            .animate()
            .setDuration(ANIMATION_TRANSITION_TIME)
            .alpha(1.0f)
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    updateShowElementsButton();
                    mHiddenLinearLayout.animate().setListener(null);
                }
            })
    ;

    mLastButton
            .animate()
            .setDuration(ANIMATION_TRANSITION_TIME)
            .translationY(mHiddenLinearLayoutHeight);

    // Update the high of all the elements relativeLayout
    LayoutParams layoutParams = mAllElementsRelativeLayout.getLayoutParams();

    // TODO: Add vertical margins
    layoutParams.height = mLastButton.getHeight() + mHiddenLinearLayoutHeight;
}

y este es el código para ocultar elementos de la animación:

private void hideElements() {
    // Precondition
    if (!areElementsVisible()) {
        Log.w(TAG, "The view is already non-visible. Nothing to do here");
        return;
    }

    // Animate the hidden linear layout as visible and set
    mHiddenLinearLayout
            .animate()
            .setDuration(ANIMATION_TRANSITION_TIME)
            .alpha(0.0f)
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    Log.v(TAG, "Animation ended. Set the view as gone");
                    super.onAnimationEnd(animation);
                    mHiddenLinearLayout.setVisibility(View.GONE);
                    // Hack: Remove the listener. So it won't be executed when
                    // any other animation on this view is executed
                    mHiddenLinearLayout.animate().setListener(null);
                    updateShowElementsButton();
                }
            })
    ;

    mLastButton
            .animate()
            .setDuration(ANIMATION_TRANSITION_TIME)
            .translationY(0);

    // Update the high of all the elements relativeLayout
    LayoutParams layoutParams = mAllElementsRelativeLayout.getLayoutParams();

    // TODO: Add vertical margins
    layoutParams.height = mLastButton.getHeight();
}

Tenga en cuenta que hay un simple truco en el método para ocultar la animación. En el oyente de animación mHiddenLinearLayout, tuve que eliminar el oyente en sí usando:

mHiddenLinearLayout.animate().setListener(null);

Esto se debe a que una vez que un oyente de animación se adjunta a una vista, la próxima vez que se ejecute una animación en esta vista, también se ejecutará el oyente. Esto podría ser un error en el oyente de animación.

El código fuente del proyecto está en GitHub: https://github.com/jiahaoliuliu/ViewsAnimated

¡Feliz codificación!

Actualización : para cualquier oyente conectado a las vistas, debe eliminarse después de que finalice la animación. Esto se hace usando

view.animate().setListener(null);
jiahao
fuente
Esta es la mejor respuesta
Naveen Kumar M
1
La view.animate().setListener(null);declaración me salvó el día. Esto definitivamente parece ser un error.
Michal Vician
@MichalVician Me alegro de haberlo hecho.
jiahao
8

Pude mostrar / ocultar un menú de esta manera:

MenuView.java (extiende FrameLayout)

private final int ANIMATION_DURATION = 500;

public void showMenu()
{
    setVisibility(View.VISIBLE);
    animate()
            .alpha(1f)
            .setDuration(ANIMATION_DURATION)
            .setListener(null);
}

private void hideMenu()
{
    animate()
            .alpha(0f)
            .setDuration(ANIMATION_DURATION)
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    setVisibility(View.GONE);
                }
            });
}

Fuente

Nelson Almendra
fuente