Sunday, December 12, 2010

Custom Fade in - Fade out animation in a custom view

I was in a situation to implement a fade in - fade out animations between two pictures
in a custom view.

I have an array of bitmaps passed to my custom view. I need to do animation between the images.

1st Image - Shown first. 2nd Image - is Lying behind it.

Required sequence of image display is like below




1st Image - Fades out
2nd Image - Fades in // Both actions parallely

As soon as 2nd image is seen, bring the 3rd image and draw it behind the 2nd image.

2nd Image - Fades out
3rd Image - Fades In // Both actions parallely.

Considering 4 images are in the array.

4th Image - Fades out
1st Image - Fades In. // So this loop continues with number of images in the array.



Lets see how we can achieve this...!!

1 - First thing to know is, using 'Paint' instance we can set alpha value for the paint. Which means,



if alpha -> 0, then the content drawn using this paint will not be seen at all.
Complete transparency will be provided.

if alpha -> 255, then the content will be shown without transparency. i.e literally means, u cannot see contents if any drawn behind it.

if alpha -> 100, then paritally you can see some content(if any) behind the current content.



Using this setAlpha() api of paint, fade -in & fade -out of two images can be applied simultaneously.

2 - We need to do the animation repeatedly over a peroid of time. So we need either a thread or runnable. Since thread is costly, runnables are preferred. In this case we need two threads.



1 - Perform / Decide, when to change the pictures. ( ex. every 5 sec)
2 - Change the alpha values of foreground / backgroud images to bring the fade out - fade in effect. ( ex. 500 milli seconds each alpha value persists )



3 - We need to create two paints, one for foreground image and another for background image.
i.e Paint mForeGroundPaint;
Paint mBackGroundPaint;

4 - Load the bunch of images you need to shuffle across in a ArrayList.

5 - Have a global picCount variable to keep track of current count of images in the arrayList.

6 - Important stuff to remember. Since we are using runnables, which is different from main UI thread, we need to have a handler to send a message to main thread and call the drawing of foreground / background images. Else you will see a crash.

7 - Once the picCount reaches > ArrayList count, make it to zero and shuffle the foreground / background images accordingly.

8 - This runnables will keep running as long the instance of 'customView' life.So make sure when you want to stop it, remove the Runnable from the Handler.

mHandler.removeCallbacks(mAnimationTask);



fadeinout.java
-----------------

  

package com.android.fadein;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Bitmap.Config;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;

public class fadeinout extends Activity {

public class customview extends View
{
Paint mPaint;
Paint mForeGroundPaint;
Paint mBackGroundPaint;
Rect rect;
ArrayList attachmentList;
int picCount;
int foregrndalpha = 255;
int backgrndalpha = 0;
Runnable mAnimationTask;
H mHandler = new H();
Bitmap contentBitmap;
Canvas Backgroundcanvas;
Bitmap mAttachmentbackGround;
Bitmap mAttachmentforeGround;

Context mContext;
public customview(Context context)
{
super(context);
mContext = context;
mPaint = new Paint();
mPaint.setTextSize(25);
// set Color- blue
mPaint.setColor(0xFF0000FF);
mPaint.setTextSize(16);
mForeGroundPaint = new Paint();
mBackGroundPaint = new Paint();

attachmentList = new ArrayList();
attachmentList.add(BitmapFactory.decodeResource(mContext.getResources(),R.drawable.bear));
attachmentList.add(BitmapFactory.decodeResource(mContext.getResources(),R.drawable.tiger));
attachmentList.add(BitmapFactory.decodeResource(mContext.getResources(),R.drawable.bird));
attachmentList.add(BitmapFactory.decodeResource(mContext.getResources(),R.drawable.fish));

/* assign the background, foreground images */
picCount = 0;
mAttachmentforeGround = attachmentList.get(picCount);
mAttachmentbackGround = attachmentList.get(picCount+1);

contentBitmap = Bitmap.createBitmap( 300,300, Config.ARGB_8888);
Backgroundcanvas = new Canvas(contentBitmap);

foregrndalpha = 255;
rect = new Rect();
rect.left = 10;
rect.top = 30;
rect.right = 310;
rect.bottom = 330;

populateAttachmentBitmap();
fadeInfadeOutImages();
}

/* Periodically changes the mForeGroundPaint alpha value to bring transparency so that it looks like
* forground image is fading out and background image is fading in
*/

public void fadeInfadeOutImages()
{
mAnimationTask = new Runnable()
{

public void run()
{
if(foregrndalpha > 0 )
{
if (foregrndalpha == 255) { // 155
foregrndalpha -= 100;
backgrndalpha = 100;
} else { //100
foregrndalpha -= 155;
backgrndalpha = 255;
}

mForeGroundPaint.setAlpha(foregrndalpha);
mBackGroundPaint.setAlpha(backgrndalpha);
mHandler.sendEmptyMessage(0);
mHandler.postDelayed(mAnimationTask, 500);
}
else
{
foregrndalpha = 255;
backgrndalpha = 0;
/* Once the alpha reaches zero, its time to change the background, foreground images */
if(++picCount < attachmentList.size())
{
mAttachmentforeGround = mAttachmentbackGround;
mAttachmentbackGround = attachmentList.get(picCount);
}
else
{
picCount = 0;
mAttachmentforeGround = mAttachmentbackGround;
mAttachmentbackGround = attachmentList.get(picCount);
}

mForeGroundPaint.setAlpha(foregrndalpha);
mBackGroundPaint.setAlpha(backgrndalpha);
mHandler.sendEmptyMessage(0);
mHandler.postDelayed(mAnimationTask, 3000);
}

}
};
mHandler.postDelayed(mAnimationTask, 5000);

}

/* All email animation changes to the UI thread must be sent
* via this handler to GridElementView
*/

class H extends Handler
{
public void handleMessage(Message m)
{
if(m.what == 0)
{
System.out.println("Handle message");
populateAttachmentBitmap();
invalidate();

}

}
}

public void populateAttachmentBitmap () {

Backgroundcanvas.drawBitmap(mAttachmentbackGround, null, rect, mBackGroundPaint);
Backgroundcanvas.drawBitmap(mAttachmentforeGround, null, rect, mForeGroundPaint);

}

@Override
public void onDraw(Canvas canvas)
{
canvas.drawText("Welcome to custom fadein - fadeout image animation", 10,20, mPaint);
canvas.drawBitmap(contentBitmap, null,rect, mPaint);
}

}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
customview view = new customview(this);
setContentView(view);
}
}

11 comments:

  1. Is thr a way to do this for text?

    ReplyDelete
  2. how can Use this to background image ( android:background) ???

    ReplyDelete
  3. Sorry this post deals with custom views.

    You can try out the following stuff.

    1 - Create a ViewFlipper with two images and set fadein - fade out to entry and exit animation for two images.
    2- Create a FrameLayout and add ViewFlipper as first element and add your layout as second element.
    3 - This brings the illusion of background images ( which is nothing but viewflipper) chaning the images.

    thanks,
    Mani

    ReplyDelete
  4. could you provide download links....

    ReplyDelete
  5. Nice tutorial thank you so much......

    ReplyDelete
  6. could you help me in setting this total concept for
    wallpaper.??
    how can i set this as wall paper?

    ReplyDelete
  7. same concept also work for LIVE WALLPAPERS?

    ReplyDelete
  8. how to stop animation after one complete cycle??

    ReplyDelete
  9. I have been struggling with trying to get a slideshow going, but this here was perfect! Thank you so much!

    ReplyDelete