David Janes' Code Weblog

November 23, 2009

Animated Slideshow on Android

android,code fragments,java · David Janes · 7:20 pm ·

After a brutal day of running into many Android bugs and misdocumentations, I’ve finally figured out how to create a slideshow of images for Android, with each imaging fading to the next. This is not unlike AnimationDrawable, except with a smoother and slower transition between images.

First, you need a resource file with something like this in it. The FrameLayout is the clever bit: it stacks everyone of its children on top of each other.

<FrameLayout
 android:id="@+id/frame"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
>
 <ImageView
 android:id="@+id/slide_1"
 android:layout_gravity="center_vertical"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 />
 <ImageView
 android:id="@+id/slide_2"
 android:layout_gravity="center_vertical"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 />
</FrameLayout>

Then you need code that looks like this:

public class TopListActivity
  extends Activity
{
  private static class AnimationAlphaTimer
    extends TimerTask
    implements Animation.AnimationListener
  {
    TopListActivity topList;
    Vector<BitmapDrawable> images;
    int count = 0;

    public AnimationAlphaTimer(TopListActivity _topList)
    {
      this.topList = _topList;

      this.images = new Vector<BitmapDrawable>();
      for (int i = 0; ; i++) {
      // LOAD IMAGES HERE
      }

      if (this.images.size() > 0) {
        this.topList.slide_0.setBackgroundDrawable(this.images.get(0));

        if (this.images.size() > 1) {
          this.topList.slide_1.setBackgroundDrawable(this.images.get(1));
        }
      }

      this.count = 1;
    }

    public void launch()
    {
      if (this.images.size() >= 2) {
        (new Timer(false)).schedule(this, 100);
      }
    }

    @Override
    public void run()
    {
      this.doit();
      this.cancel();
    }

    private void doit()
    {
      if ((this.count % 2) == 0) {
        AlphaAnimation animation = new AlphaAnimation(1.0f, 0.0f);
        animation.setStartOffset(3000);
        animation.setDuration(3000);
        animation.setFillAfter(true);
        animation.setAnimationListener(this);

        this.topList.slide_1.startAnimation(animation);
      } else {
        AlphaAnimation animation = new AlphaAnimation(0.0f, 1.0f);
        animation.setStartOffset(3000);
        animation.setDuration(3000);
        animation.setFillAfter(true);
        animation.setAnimationListener(this);

        this.topList.slide_1.startAnimation(animation);
      }
    }

    public void onAnimationEnd(Animation animation)
    {
      if ((this.count % 2) == 0) {
        this.topList.slide_1.setBackgroundDrawable(
          this.images.get((this.count + 1) % (this.images.size()))
        );
      } else {
        this.topList.slide_0.setBackgroundDrawable(
          this.images.get((this.count + 1) % (this.images.size()))
        );
      }

      this.count++;
      this.doit();
    }

    public void onAnimationRepeat(Animation animation)
    {
    }
    public void onAnimationStart(Animation animation)
    {
    }
  }

  @Override
  public void onResume()
  {
    super.onResume();

    (new AnimationAlphaTimer(this)).launch();
  }
}

The “create a Timer trick” in onResume is courtesy of Diego Torres. If you just try to run the animation, it’s likely just to choke.

7 comments »

  1. Satya · 2009-12-22 04:54

    thankyou very much for this useful information. can you give me complete source code for this, as I badly need this.

  2. omg dang dude you are a genuis im going to copy the source code thank you
    so much i was looking for something like this.

  3. Nice tutorial – this is what I was looking for! Just a comment, your pinkish background and light grey text makes it almost impossible to read your code tags in your blog!

  4. David Janes · 2010-05-23 06:50

    Thanks. Are you sure all the RGB channels are working on your monitor? Background is white, except code samples which are yellow. I’ve darkened up the code tag text now though.

  5. tamil · 2011-02-24 08:20

    i got the error here this.topList.slide_1.startAnimation(animation); slide_1 is shows the error

    topList.slide_0

  6. Hitesh Pamnani · 2011-09-18 00:07

    I am heartly thankful to you for providing such a wonderful code, but I am getting the following exception.

    09-18 10:31:53.843: ERROR/AndroidRuntime(344): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
    09-18 10:31:53.843: ERROR/AndroidRuntime(344):     at android.view.ViewRoot.checkThread(ViewRoot.java:2802)
    09-18 10:31:53.843: ERROR/AndroidRuntime(344):     at android.view.ViewRoot.invalidateChild(ViewRoot.java:607)
    09-18 10:31:53.843: ERROR/AndroidRuntime(344):     at android.view.ViewRoot.invalidateChildInParent(ViewRoot.java:633)
    09-18 10:31:53.843: ERROR/AndroidRuntime(344):     at android.view.ViewGroup.invalidateChild(ViewGroup.java:2505)
    09-18 10:31:53.843: ERROR/AndroidRuntime(344):     at android.view.View.invalidate(View.java:5139)
    09-18 10:31:53.843: ERROR/AndroidRuntime(344):     at android.view.View.startAnimation(View.java:8394)
    09-18 10:31:53.843: ERROR/AndroidRuntime(344):     at com.queppelin.dealsandyou.activity.MainActivity$AnimationAlphaTimer.doit(MainActivity.java:93)
    09-18 10:31:53.843: ERROR/AndroidRuntime(344):     at com.queppelin.dealsandyou.activity.MainActivity$AnimationAlphaTimer.run(MainActivity.java:73)
    09-18 10:31:53.843: ERROR/AndroidRuntime(344):     at java.util.Timer$TimerImpl.run(Timer.java:289)

    Please solve the exception as early as possible.

  7. admin · 2011-09-18 04:44

    My understanding of Android stuff is much more sophisticated now.

    Take out the Timer stuff — that’s not the Android way — and replace it with something like this code:

    new Handler() {
        @Override
        public void handleMessage(Message msg)
        {
            AnimationAlphaTimer.this.doit();
        }
    }.sendEmptyMessageDelayed(0, 6000);
    

    You’ll have to play with that a bit for names, as my original code has evolved quite a bit since then.

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress

Switch to our mobile site