Thursday, July 14, 2011

Android Animation - fading in an image

For once, I'm going to do something that's totally for fun, or at least, totally for aesthetics. What's going on is I currently display an image if the user gets all the questions right in a given level. Right now it pops up and disappears rather abruptly. I'd like create a kind of fade-in, fade-out effect for this. I think it will look pretty cool.

I had a book, what was it, that showed effects for and Android game. Let me check. Ah yes, this one:

http://www.amazon.com/Teach-Yourself-Android-Application-Development/dp/0321673352

It was pretty good, and they had a game which did some animations of an image, like spinning it. Let's see if I can find that code.

Ah, here we go:

One great way to add zing to your splash screen would be to add some animation.
The Android platform supports four types of graphics animation:
. Animated GIF images—Animated GIFs are self-contained graphics files with
multiple frames.

// no

. Frame-by-frame animation—The Android SDK provides a similar mechanism
for frame-by-frame animation in which the developer supplies the
individual graphic frames and transitions between them (see the
AnimationDrawable class).

// not sure

. Tweened animation—Tweened animation is a simple and flexible method of
defining specific animation operations that can then be applied to any view
or layout.

// yeah

. OpenGL ES—Android’s OpenGL ES API provides advanced three-dimensional
drawing, animation, lighting, and texturing capabilities.

// no

For your application, the tweened animation makes the most sense. Android provides
tweening support for alpha (transparency), rotation, scaling, and translating
(moving) animations.

// I need the alpha and maybe the scaling.

With tweened animation, you create an animation sequence, either programmatically
or by creating animation resources in the /res/anim directory. Each animation
sequence needs its own XML file, but the animation may be applied to any
number of View controls.

You can use the built-in animations provided in the android.R.anim class.

Adding Animation Resources
For your splash screen, you need to create three custom animations in XML and
save them to the /res/anim resource directory: fade_in.xml, fade_in2.xml, and
custom_anim.xml.


The first animation, fade_in.xml, simply fades its target from an alpha value of 0
(transparent) to an alpha value of 1 (opaque) over the course of 2500 milliseconds,
or 2.5 seconds. There is no built-in animation editor in Eclipse. The XML for the
fade_in.xml animation looks like this:

xmlns:android=”http://schemas.android.com/apk/res/android”
android:shareInterpolator=”false”>
android:fromAlpha=”0.0”
android:toAlpha=”1.0”
android:duration=”2500”>






// This is sounding good. This is exactly what I'm looking for. Maybe I should just try this to start out.


You can apply this animation to the top TextView control with your title text.
Next, you create the fade_in2.xml animation.

// let look at that one;



xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="2500"
android:startOffset="2500">





This animation does exactly the same thing as the fade_in animation, except that you set the startOffset attribute
to 2500 milliseconds.

This means that this animation will actually take 5 seconds total: It waits 2.5 seconds and then fades in for 2.5 seconds.

// Ok, so it waits 2.5 seconds, then fades in.

Because 5 seconds is long enough to display the splash screen, you should plan to listen for fade_in2
to complete and then transition to the main menu screen.

// Listen?

Finally, you need some fun animation sequence for the TableLayout graphics. In
this case, your animation set contains multiple, simultaneous operations: a rotation,
some scaling, and an alpha transition. As a result, the target View spins into existence.
The custom_anim.xml file looks like this:



xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
android:duration="2000" />
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="2000">

android:pivotX="50%"
android:pivotY="50%"
android:fromXScale=".1"
android:fromYScale=".1"
android:toXScale="1.0"
android:toYScale="1.0"
android:duration="2000" />




This looks cool - it looks like it grows. I can try it out. I think I will just want a fade-in and fade-out, though.


As you can see, the rotation operation takes 2 seconds to rotate from 0 to
360 degrees, pivoting around the center of the view. The alpha operation should
look familiar; it simply fades in over the same 2-second period. Finally, the scale
operation scales from 10% to 100% over the same 2-second period. This entire animation
takes 2 seconds to complete.
After you have saved all three of your animation files, you can begin to apply the
animations to specific views.

// Ok, why don't I try them all, and then start pulling stuff I don't need out.

First I'll create an "anim" directory under "res". Actually, I'll just copy it in from the downloaded code.

Animating Specific Views
Animations must be applied and managed programmatically. Remember, costly
operations, such as animations, should be stopped if the application is paused for
some reason. The animation can resume when the application comes back into the
foreground.

// Ok...

Let’s start with a simplest case: applying the fade_in animation to your title
TextView control, called TextViewTopTitle. All you need to do is retrieve an
instance of your TextView control in the onCreate() method of the
QuizSplashActivity class, load the animation resource into an Animation object,
and call the startAnimation() method of the TextView control:


TextView logo1 = (TextView) findViewById(R.id.TextViewTopTitle);
Animation fade1 = AnimationUtils.loadAnimation(this, R.anim.fade_in);
logo1.startAnimation(fade1);


// Ok, this looks good. I'll just apply it to the image. Hmmm - I'll have to apply it to the text links as well. Anyway.

Let's see how this works out:



// Get the image widget
image = (ImageView) findViewById(R.id.image);

// Set the image
image.setImageResource(imageResourceIds[index]);

// Fade the image in
Animation fade1 = AnimationUtils.loadAnimation(this, R.anim.fade_in);
image.startAnimation(fade1);


Awesome! That was a gorgeous fade-in.



When an animation must be stopped—for instance, in the onPause() method of the
activity—you simply call the clearAnimation() method. For instance, the following
onPause() method demonstrates this for the corner logos:


@Override
protected void onPause() {
super.onPause();
// Stop the animation
TextView logo1 = (TextView) findViewById(R.id.TextViewTopTitle);
logo1.clearAnimation();
TextView logo2 = (TextView) findViewById(R.id.TextViewBottomTitle);
logo2.clearAnimation();
// ...



So, let's put the on pause in.



@Override
protected void onPause() {
super.onPause();

image = (ImageView) findViewById(R.id.image);
image.clearAnimation();
}


Ok, what would be cool is if we fade it out, too.




@Override
public boolean onTouch(View arg0, MotionEvent arg1) {
// Fade the image in
Animation fadeOut = AnimationUtils.loadAnimation(this, R.anim.fade_out);
image.startAnimation(fadeOut);

finish();
return false;
}




And fade_out looks like this:




xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration="2500">





Well, I'm getting ahead of myself. I think I'll need to add an animation listener, because it disappears right away.

What I'd like to do before that, is implement the animation for all the objects in the view, so they fade in together.

In addition to applying animations to individual View controls, you can also apply
them to each child View control within a Layout (such as TableLayout and each
TableRow), using LayoutAnimationController.

To animate View controls in this fashion, you must load the animation, create
LayoutAnimationController, configure it as necessary, and then call the layout’s
setLayoutAnimation() method.

For example, the following code loads the custom_
anim animation, creates a LayoutAnimationController, and then applies it to
each TableRow in the TableLayout control:


Animation spinin = AnimationUtils.loadAnimation(this, R.anim.custom_anim);
LayoutAnimationController controller =
new LayoutAnimationController(spinin);
TableLayout table = (TableLayout) findViewById(R.id.TableLayout01);
for (int i = 0; i < table.getChildCount(); i++) {
TableRow row = (TableRow) table.getChildAt(i);
row.setLayoutAnimation(controller);
}



Well, it doesn't work. The problem is that my layout isn't a table. I can get subviews, but they don't seem to have the setLayoutAnimation. I'll just do them all individually, and forget about the fade out.

Ah, wait. How about this:
LinearLayout layout = (LinearLayout) findViewById(R.id.layout_root);
for (int i = 0; i < layout.getChildCount(); i++) {
View view = (View) layout.getChildAt(i);
view.startAnimation(fade1);
}

No - the problem is, it works, but everything goes dark while it waits for the image to appear.

Ok, let's finish it up by setting up an animation listener for the fade out.

Of your animations, the fade_in2 animation takes the longest, at 5 seconds total.
This animation is therefore the one you want to trigger your transition upon.

You do so by creating an AnimationListener object, which has callbacks for the animation
life cycle events: start, end, and repeat. In this case, only the onAnimationEnd()
method has an interesting implementation.

Here is the code to create the AnimationListener and implement the onAnimationEnd() callback:


Animation fade2 = AnimationUtils.loadAnimation(this, R.anim.fade_in2);
fade2.setAnimationListener(new AnimationListener() {

public void onAnimationEnd(Animation animation) {
startActivity(new Intent(QuizSplashActivity.this,
QuizMenuActivity.class));
QuizSplashActivity.this.finish();
}
});


So, lets try it -



@Override
public boolean onTouch(View view, MotionEvent arg1) {

// Fade out the image
Animation fadeOut = AnimationUtils.loadAnimation(this, R.anim.fade_out);
view.startAnimation(fadeOut);

fadeOut.setAnimationListener(new AnimationListener() {

public void onAnimationEnd(Animation animation) {
NextLevelActivity.this.finish();
}

@Override
public void onAnimationRepeat(Animation arg0) {
// TODO Auto-generated method stub

}

@Override
public void onAnimationStart(Animation arg0) {
// TODO Auto-generated method stub

}
});



Yes, it work. But, I think if the user presses the button, the don't want to wait. They've seen it. I really don't like it when some smartass developer tries to take control of my time. Forget it.

What I can do is fade the picture if they let it time out. Why not?





// set up a timer so the dialog automatically disappears
int totalMsecs = 1 * 5000; // 5 seconds
int callInterval = 1000;

// The countdown timer
new CountDownTimer(totalMsecs, callInterval) {

// required
public void onTick(long millisUntilFinished) {
}

// done
public void onFinish() {

Animation fadeOut = AnimationUtils.loadAnimation(NextLevelActivity.this, R.anim.fade_out);
NextLevelActivity.this.mImage.startAnimation(fadeOut);


fadeOut.setAnimationListener(new AnimationListener() {

public void onAnimationEnd(Animation animation) {
NextLevelActivity.this.finish();
}

@Override
public void onAnimationRepeat(Animation arg0) {
// TODO Auto-generated method stub

}

@Override
public void onAnimationStart(Animation arg0) {
// TODO Auto-generated method stub

}
});
}

}.start();

}


Well, I'm undecided now. What I'd like to do is spin in the "congratulation" *text", but fade in the image. Phew.


public void onFinish() {

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



LinearLayout layout = (LinearLayout) findViewById(R.id.layout_root);
for (int i = 0; i < layout.getChildCount(); i++) {
View view = (View) layout.getChildAt(i);
view.startAnimation(fadeOut);
}




Yes, that's good.

Now, how about that spinning text?

Well, let's try that whole customAnim.xml



xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
android:duration="2000" />
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="2000">

android:pivotX="50%"
android:pivotY="50%"
android:fromXScale=".1"
android:fromYScale=".1"
android:toXScale="1.0"
android:toYScale="1.0"
android:duration="2000" />



Ok. I've got go listen to some blues.I'll finish this up tomorrow!

No comments:

Post a Comment