En función de la versión de Android que utilicemos y del fabricante, la transición entre Activities se realizará aplicando determinada animación (aunque puede desactivarse). Android proprociona dos grandes tipos de animaciones:
- Property animation: permite animar elementos de la vista modificando también sus propiedades como por ejemplo el fondo. Fueron introducidas en Honeycomb, pero pueden utilizarse en Android 2 gracias a la librería de compatibilidad aunque lo más recomendable es recurrir a NineOldAndroids de nuestro amigo Jake Wharton.
- View Animation: Permite realizar animaciones muy básicas de View completos.
En este tutorial vamos a utilizar el segundo tipo (ya se utilizó en el tip #12) para personalizar las transiciones entre Activities de forma muy sencilla a través de xml, proporcionando unos ejemplos listos para copiar y pegar. No se entrará en muchos detalles sobre las animaciones, sólo se darán las nociones básicas.
Animaciones disponibles y proyecto de ejemplo
Contamos con los siguientes tipos de animaciones las cuales puden ser combinadas entre sí.
- alpha: Opacidad del View, desde 0 (transparente) hasta 1. Lo combinaremos con las demás animaciones para conseguir efectos vistosos.
- scale: cambia el tamaño con respecto a un punto de referencia. Lo usaremos para simular efectos de zoom.
- translate: desplazamiento
- rotate: realiza una rotación en 2D. No se usará en este artículo.
Estas animaciones puden ser definidas programáticamente o en xml los cuales se ubicarán en /res/anim/. Para aplicarlas y jugar con ellas, vamos a crear un proyecto compatible con Android 2.1 con 2 activities para navegar entre ambas aplicando distintas animaciones. Las animaciones para las transiciones entre activities se indican tras invocar el método startActivity con el método overridePendingTransition al que se le indicará la animación de la Activity que «desaparece» y la de la nueva Activity que se va a mostrar. Los layout para estas dos activities de prueba son los siguientes:
<?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:background="@android:color/background_dark" android:gravity="center" android:orientation="vertical" > <Button android:id="@+id/button" android:layout_width="180dp" android:layout_height="wrap_content" android:onClick="forwardZoom" android:text="@string/forwardZoom" android:textAppearance="?android:attr/textAppearanceMediumInverse" /> <Button android:id="@+id/button2" android:layout_width="180dp" android:layout_height="wrap_content" android:layout_marginTop="30dp" android:onClick="left" android:text="@string/left" android:textAppearance="?android:attr/textAppearanceMediumInverse" /> <Button android:id="@+id/button3" android:layout_width="180dp" android:layout_height="wrap_content" android:layout_marginTop="30dp" android:onClick="fade" android:text="@string/fade" android:textAppearance="?android:attr/textAppearanceMediumInverse" /> <Button android:id="@+id/button4" android:layout_width="180dp" android:layout_height="wrap_content" android:layout_marginTop="30dp" android:onClick="byDefault" android:text="@string/bydefault" android:textAppearance="?android:attr/textAppearanceMediumInverse" /> </LinearLayout>
<?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:background="@android:color/background_light" android:gravity="center" android:orientation="vertical" > <Button android:id="@+id/button1" android:layout_width="180dp" android:layout_height="wrap_content" android:layout_gravity="center" android:onClick="zoomBack" android:text="@string/zoomBack" android:textAppearance="?android:attr/textAppearanceMediumInverse" /> <Button android:id="@+id/button2" android:layout_width="180dp" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="30dp" android:onClick="right" android:text="@string/right" android:textAppearance="?android:attr/textAppearanceMediumInverse" /> <Button android:id="@+id/button3" android:layout_width="180dp" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="30dp" android:onClick="fade" android:text="@string/fade" android:textAppearance="?android:attr/textAppearanceMediumInverse" /> <Button android:id="@+id/button4" android:layout_width="180dp" android:layout_height="wrap_content" android:layout_marginTop="30dp" android:onClick="back" android:text="@string/bydefaultback" android:textAppearance="?android:attr/textAppearanceMediumInverse" /> </LinearLayout>
Las activities también son tremedamente simples ya que se limitan a aplicar las animaciones
package com.danielme.android.transitions; import com.danielme.android.transitions.R; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; /** * * @author danielme.com * */ public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void forwardZoom(View button) { startActivity(new Intent(this, SecondActivity.class)); overridePendingTransition(R.anim.zoom_forward_in, R.anim.zoom_forward_out); } public void left(View button) { startActivity(new Intent(this, SecondActivity.class)); overridePendingTransition(R.anim.left_in, R.anim.left_out); } public void fade(View button) { startActivity(new Intent(this, SecondActivity.class)); overridePendingTransition(R.anim.fade_in, R.anim.fade_out); } public void byDefault(View button) { startActivity(new Intent(this, SecondActivity.class)); } }
package com.danielme.android.transitions; import com.danielme.android.transitions.R; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; /** * * @author danielme.com * */ public class SecondActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_second); } public void zoomBack(View button) { startActivity(new Intent(this, MainActivity.class)); overridePendingTransition(R.anim.zoom_back_in, R.anim.zoom_back_out); } public void fade(View button) { startActivity(new Intent(this, MainActivity.class)); overridePendingTransition(R.anim.fade_in, R.anim.fade_out); } public void right(View button) { startActivity(new Intent(this, MainActivity.class)); overridePendingTransition(R.anim.right_in, R.anim.right_out); } public void back(View button) { super.onBackPressed(); } }
El interés, por lo tanto, está en los xml con las animaciones que vamos a ir viendo a continuación. NOTA: para que se puedan apreciar con claridad, las animaciones se hacen con la suficiente lentitud.
Zoom forward
Es un desplazamiento en el que la Activity actual se va hacia el fondo y se difumina, desapareciendo al ocupar el 70% de la pantalla:
zoom_forward_out
<?xml version="1.0" encoding="UTF-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/decelerate_interpolator" android:zAdjustment="top" > <scale android:duration="600" android:fromXScale="1.0" android:fromYScale="1.0" android:pivotX="50%p" android:pivotY="50%p" android:toXScale=".7" android:toYScale=".7" /> <alpha android:duration="600" android:fromAlpha="1.0" android:toAlpha="0" /> </set>
La nueva Activity aparece «desde arriba» hasta ocupar toda la pantalla en el momento en el que la Activity de origen desaparece
zoom_forward_in
<?xml version="1.0" encoding="UTF-8"?> <scale xmlns:android="http://schemas.android.com/apk/res/android" android:duration="600" android:fromXScale="1.5" android:fromYScale="1.5" android:interpolator="@android:anim/decelerate_interpolator" android:pivotX="50%p" android:pivotY="50%p" android:toXScale="1.0" android:toYScale="1.0" />
Zoom back
Simula el efecto contrario al anterior para volver de la segunda Activity a la primera (la nueva Activity «emerge» desde el fondo (70%)).
zoom_back_out.xml
<?xml version="1.0" encoding="UTF-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/decelerate_interpolator" android:zAdjustment="top" > <scale android:fromXScale="1" android:fromYScale="1" android:pivotX="50%p" android:pivotY="50%p" android:toXScale="0.7" android:toYScale="0.7" android:duration="600"/> <alpha android:fromAlpha="1.0" android:toAlpha="0" android:duration="600"/> </set>
zoom_back_in.xml
<?xml version="1.0" encoding="UTF-8"?> <scale xmlns:android="http://schemas.android.com/apk/res/android" android:duration="600" android:fromXScale="0.7" android:fromYScale="0.7" android:interpolator="@android:anim/decelerate_interpolator" android:pivotX="50%p" android:pivotY="50%p" android:toXScale="1" android:toYScale="1" />
Desplazamiento hacia la izquierda
Las Activities se muestran contínuas y se desplazan a la izquierda hasta ocultarse completamente la primera Activity (de ahí que sea desplazada hasta la posición -100%).
left_out.xml
<?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500" android:fromXDelta="0" android:toXDelta="-100%p" android:interpolator="@android:anim/linear_interpolator" />
left_in.xml
<?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500" android:fromXDelta="100%p" android:toXDelta="0" android:interpolator="@android:anim/linear_interpolator" />
Desplazamiento hacia la derecha
La animación contraria a la anterior, las dos activities forman una imagen continúa que ahora se desplaza hacia la derecha, quedando sólo visble la Activity destino.
right_out.xml
<?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500" android:fromXDelta="0" android:interpolator="@android:anim/linear_interpolator" android:toXDelta="100%p" />
right_in.xml
<?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500" android:fromXDelta="-100%p" android:interpolator="@android:anim/linear_interpolator" android:toXDelta="0" />
Fade-Desvanecer
Animación alpha en la que Activity actual se vuelve totalmente trasparente mientras que al mismo tiempo la otra se hace opaca.
fade_out.xml
<?xml version="1.0" encoding="UTF-8"?> <alpha xmlns:android="http://schemas.android.com/apk/res/android" android:duration="800" android:fromAlpha="1.0" android:interpolator="@android:anim/accelerate_interpolator" android:repeatCount="0" android:toAlpha="0.0" />
fade_in.xml
<?xml version="1.0" encoding="UTF-8"?> <alpha xmlns:android="http://schemas.android.com/apk/res/android" android:duration="800" android:fromAlpha="0.0" android:interpolator="@android:anim/accelerate_interpolator" android:repeatCount="0" android:toAlpha="1.0" />
Animación por defecto
La animación que muestra el último botón es simplemente la que el dispositivo aplica por defecto tanto al inciar una Activity como al hacer back. Por ejemplo, en el emulador para Jelly Bean es la siguiente (muy similar a la de zoom que hemos visto):
En Android 2.1 tenemos los desplazamientos laterales que hemos visto.
El proyecto completo para Eclipse ADT se encuentra en Github. Para más información sobre cómo utilizar GitHub, consultar este artículo.
Diseño Android: Transiciones entre activities con Shared Element
Tip Android #12: animar mostrar/ocultar layout con desplazamientos
Hola he puesto las transcisiones, todo bien, en el emulador de android mi aplicaciones si las hace perfectamente, pero al momento que construyo la apk y la paso al telefono no me las reproduce! no se a que se deba tengo un LG Optimus Black android 4.0.4, rom custom ICS de Huexxx, a que se debe que no me funciona?
Es muy extraño que no te funcione ninguna ya que son las animaciones «de toda la vida» de Android. En mi ACE por ejemplo si combino la traslación con alfa no funciona el efecto alfa pero sí la traslación. Comprueba que tienes activadas las animaciones en Android, creo que solian estar dentro de la sección pantalla (depende de la versión y el dispositivo).
Hola, muy buen tutorial, solo tengo una duda, como hago para que la animaci’on comience sola al cargarse la activity? tengo que hacer un metodo con el contenido del boton start y llamarlo desde el evento onStart? en realidad probé eso pero al pasar las imagenes no funciona el fade_out.