Tip Android #31: Image Slider con ImageSwitcher

  1. 24/10/2013 (Primera publicación)
  2. 15/08/2015: Actualizado a Lollipop, con trol de salida de la Activity

android tip

Hoy en día en portales web los conocidos como “Image Slider” o carrusel de imágenes son elementos habituales y existen numerosas implementaciones, muchas basadas en jQuery como Camera o Nivo Slider. En este tip se va a implementar algo parecido pero usando sólo la SDK de Android. Se reutilizarán los wallpapers de Ubuntu de los tip 25 y 26 pero con la resolución reducida para evitar su reescalado.

La idea es utilizar el widget ImageSwitcher que permite cambiar la imagen de un ImageView aplicando una animación tanto a la imagen actual como a la nueva que aparece. Las animaciones son las clásicas de Android que ya vimos en el artículo Diseño Android: Transiciones entre Activities, de hecho se van a reutilizar las animaciones “fade in” y “fade out” para hacer aparecer y desaparecer las imágenes de forma elegante.

Por otra parte, el carrusel de imágenes será automático, esto es, las imágenes se irán mostrando sucesivamente cada cierto intervalo tiempo. Esto lo podemos conseguir mediante la clase Timer que de forma asíncrona cada cierto intervalo de tiempo realiza una acción, en nuestro caso cambiar la imagen.

En primer lugar, veamos el layout. Muestra centrado un ImageSwitcher así como los botones para iniciar y detener el carrusel.

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_above="@+id/buttons"
        android:gravity="center" >

        <ImageSwitcher
            android:id="@+id/imageSwitcher"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >
        </ImageSwitcher>
        
    </LinearLayout>

    <LinearLayout
        android:id="@+id/buttons"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true" >

        <Button
            android:id="@+id/buttonStart"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="start"
            android:text="@string/start" />

        <Button
            android:id="@+id/buttonStop"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="stop"
            android:text="@string/stop" />
    </LinearLayout>

</RelativeLayout>

Y ahora vamos con el código de la Activity, que muestra un uso básico de ImageSwitcher y Timer; al ImageSwitcher le proporcionamos las dos animaciones para realizar el cambio de imagen y a la hora de utilizar el Timer hay que hacer dos consideraciones:

  • El cambio de imagen ha de ejecutarse en el UI Thread, esto es, el hilo de la aplicación que puede modificar la interfaz gráfica.Para ello se utiliza el método
    runOnUiThread.
  • Una vez que el Timer se lanza, es más que recomendable para mejorar el rendimiento de la aplicación evitar que se continúe ejecutando una vez que el usuario ha salido de la Activity o de la aplicación. Este control se realiza sobreescribiendo el método onPause para cancelar el timer siempre que la Activity se envíe al segundo plano o se destruya.

    package com.danielme.tipsandroid.imageslider;
    
    import java.util.Timer;
    import java.util.TimerTask;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    import android.view.animation.Animation;
    import android.view.animation.AnimationUtils;
    import android.widget.ImageSwitcher;
    import android.widget.ImageView;
    import android.widget.ViewSwitcher.ViewFactory;
    
    /**
     * 
     * @author danielme.com
     *
     */
    public class MainActivity extends Activity {
    	private ImageSwitcher imageSwitcher;
    
    	private int[] gallery = { R.drawable.a, R.drawable.b, R.drawable.c,
    			R.drawable.d, R.drawable.e, R.drawable.f };
    
    	private int position;
    
    	private static final Integer DURATION = 2500;
    
    	private Timer timer = null;
    
    	@Override
    	public void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		imageSwitcher = (ImageSwitcher) findViewById(R.id.imageSwitcher);
    		imageSwitcher.setFactory(new ViewFactory() {
    
    			public View makeView() {
    				return new ImageView(MainActivity.this);
    			}
    		});
    
    		// Set animations
    		// https://danielme.com/2013/08/18/diseno-android-transiciones-entre-activities/
    		Animation fadeIn = AnimationUtils.loadAnimation(this, R.anim.fade_in);
    		Animation fadeOut = AnimationUtils.loadAnimation(this, R.anim.fade_out);
    		imageSwitcher.setInAnimation(fadeIn);
    		imageSwitcher.setOutAnimation(fadeOut);
    	}
    
    	// ////////////////////BUTTONS
    	/**
    	 * starts or restarts the slider
    	 * 
    	 * @param button
    	 */
    	public void start(View button) {
    		if (timer != null) {
    			timer.cancel();
    		}
    		position = 0;
    		startSlider();
    	}
    
    	public void stop(View button) {
    		if (timer != null) {
    			timer.cancel();
    			timer = null;
    		}
    	}
    
    	public void startSlider() {
    		timer = new Timer();
    		timer.scheduleAtFixedRate(new TimerTask() {
    
    			public void run() {
    				// avoid exception:
    				// "Only the original thread that created a view hierarchy can touch its views"
    				runOnUiThread(new Runnable() {
    					public void run() {
    						imageSwitcher.setImageResource(gallery[position]);
    						position++;
    						if (position == gallery.length) {
    							position = 0;
    						}
    					}
    				});
    			}
    
    		}, 0, DURATION);
    	}
    
    	// Stops the slider when the Activity is going into the background
    	@Override
    	protected void onPause() {
    		super.onPause();
    		if (timer != null) {
    			timer.cancel();
    		}
    	}
    
    	@Override
    	protected void onResume() {
    		super.onResume();
    		if (timer != null) {
    			startSlider();
    		}
    
    	}
    
    }
    

    El resultado final en Jelly Bean:


    El proyecto completo se encuentra en Github. Para más información sobre cómo utilizar GitHub, consultar este artículo.

    << TIPS ANDROID

23 Responses to Tip Android #31: Image Slider con ImageSwitcher

  1. Diego dice:

    Muy buen tuto😀 te felicito pero me quedo una duda, ¿como podrias sacar imagenes pero desde la SD en vez de R.drawable?

  2. Jerry dice:

    Hola buen día… está muy interesante y muy padre el aporte pero tengo una duda. Estoy tratando de implementar un slider como el tuyo en un proyecto con Fragments, pero cuando me marca un error en el return new ImageView(MainActivity.this);… me dice que el constructor no está definido… Espero me puedas echar la mano ya que es un proyecto escolar… De antemano muchas gracias y muy buen aporte

    • danielme.com dice:

      De entrada para obtener en un Fragment la Activity asociada debes usar getActivity().

      • jerryh5 dice:

        Así es ya lo hice y eclipse no me marca error… pero al momento de correr la app colapsa😦

      • jerryh5 dice:

        No se si lo hice mal pero en return new ImageView(MainActivity.this); cambien el main activity por el getActivity() y eclipse no marca error pero la aplicación colapsa cuando se corre en el celular

  3. Richard Arce dice:

    Hola quiciera saber como ejecutar una actividad una ves finalizado el bucle yo modifique el codigo para que no tenga botones, lo puse en fullscreen la activity y luego de ejecutar todo cuando llega a la posicion 0 intento finalizar el hilo y ejecutar una actividad como podia lograrlo gracias

    • danielme.com dice:

      No hay que hacer nada particular, dentro del método run al llegar a la posición cero lanza la activity que quieras de forma habitual y para el slider con el método cancel del timer (es lo que se hace al pulsarse stop), incluso puedes finalizar la activity (finish) si no quieres que se restaure al pulsar back.

  4. Zezo Hacker dice:

    hey bro how can i can make it run automatically , that mean no need to pres start to make it start

  5. rene cervantes dice:

    geneal🙂 excelente tip, me sirvio mucho, solo tengo una duda como le hago para que sea automatico, sin el boton de start.
    soy nuevo desarrollando en android
    saludos🙂

    • danielme.com dice:

      Utiliza estos métodos:
      @Override
      protected void onPause() {
      super.onPause();
      timer.cancel();
      }

      @Override
      protected void onResume() {
      super.onResume();
      startSlider();

      }
      El slider se iniciará siempre al mostrarse la pantalla y se detendrá al salir de ella.

  6. RGM dice:

    Parcero, de hecho hay una forma mas sencilla de hacerlo. Usa el metodo del Image switcher que se llama postDelayed, te dejo la idea basica:
    imageSwitcher.postDelayed(new Runnable() {
    @Override
    public void run() {

    }
    }, 1000);
    De esta forma no tienes que meterme con el thread principal del ui, el metodo lo llama solo.
    Cualquier correccion es bienvenida

  7. rehp dice:

    si quiero dar click a una imagen mientras pasa como puedo hacer?

  8. Mario Pérez dice:

    Excelente post, claro y sencillo.

    Estoy intentando usar el codigo tal cual está acá para luego ir modificandolo, pero me da error en las siguientes lineas:

    Animation fadeIn = AnimationUtils.loadAnimation(this, R.anim.fade_in);
    Animation fadeOut = AnimationUtils.loadAnimation(this, R.anim.fade_out);

    Cannot resolve symbol ‘fade_in’ y ‘fade_out’

    Todo el codigo está tal cual, es el único error que muestra, por favor espero pueda ayudarme. Saludos

    • Mario Pérez dice:

      Disculpa, ya solucioné jeje leyendo un poco me di cuenta que tenía que crear los xml de las transiciones, lo siento mucho. buen post, gracias.. Saludos

  9. Hola, excelente código : ). Tengo una duda, las imagenes se aparecen repentinamente, no va una por una. Es decir cambiar muy rápido de imagen a imagen aunque tengo los tiempos descritos aquí en el tutorial

    • Carloso dice:

      A mi me sucedió lo mismo, mas cuando utilizaba imágenes un poco grandes. Lo que solucionó este problema fue sacar toda la parte de TImer y utilizar el método “postDelayed” como mencionó RGM más arriba. Por las dudas copio nuevamente el código que el publicó.

      imageSwitcher.postDelayed(new Runnable() {
      @Override
      public void run() {

      }
      }, 1000);

  10. rjescobar dice:

    gracias por el tutorial, una pregunta como puedo agregar botones dentro de la imagen para asi ver la transicion

  11. alejandro dice:

    me sale este error java.lang.NullPointerException

  12. Hola, antes que nada gracias por el tutorial. Como puedo hacer para lanzar la animación en el onCreate de la activity? en realidad intenté hacerlo pero no funciona el fade_out, van apareciendo de golpe las imágenes.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: