Reputation: 41
I'm trying to animate a ball image coming into the screen, shifting position within the screen and go back out of the screen. I want to do this in form of 3 animations; ball_in, ball_shift and ball_out, as well as being able to decide when to go from one animation to the other.
This is the code I got so far;
Main.xml
<?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">
<ImageView android:id="@+id/ballImage" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_margin="5px"
android:src="@drawable/red_ball"
/>
</RelativeLayout>
Main activity
public class AnimationTest extends Activity
{
AnimationDrawable ballAnimation;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final ImageView ballImage = (ImageView) findViewById(R.id.ballImage);
final Animation ballOutAnimation = AnimationUtils.loadAnimation(this, R.anim.ball_out);
final Animation ballShiftAnimation = AnimationUtils.loadAnimation(this, R.anim.ball_shift);
ballShiftAnimation.setAnimationListener( new AnimationListener()
{
@Override
public void onAnimationEnd(
Animation animation) {
ballImage.startAnimation(ballOutAnimation);
}
@Override
public void onAnimationRepeat(
Animation animation) {}
@Override
public void onAnimationStart(
Animation animation) {}
});
final Animation ballInAnimation = AnimationUtils.loadAnimation(this, R.anim.ball_in);
ballInAnimation.setAnimationListener( new AnimationListener()
{
@Override
public void onAnimationEnd(
Animation animation) {
ballImage.startAnimation(ballShiftAnimation);
}
@Override
public void onAnimationRepeat(
Animation animation) {}
@Override
public void onAnimationStart(
Animation animation) {}
});
ballImage.startAnimation(ballInAnimation);
}
}
ball_in.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_decelerate_interpolator">
<translate
android:fromXDelta="150"
android:toXDelta="0"
android:fromYDelta="0"
android:toYDelta="0"
android:duration="2000"
android:startOffset="0"
/>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_decelerate_interpolator">
<translate
android:fromXDelta="0"
android:toXDelta="0"
android:fromYDelta="-150"
android:toYDelta="0"
android:duration="1500"
android:startOffset="500"
/>
</set>
</set>
ball_shift.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_decelerate_interpolator">
<translate
android:fromXDelta="0"
android:toXDelta="130"
android:fromYDelta="0"
android:toYDelta="220"
android:duration="2000"
android:startOffset="0"
android:fillAfter="true"
/>
<scale
android:fromXScale="1.0"
android:toXScale="0.623"
android:fromYScale="1.0"
android:toYScale="0.623"
android:duration="2000"
android:startOffset="0"
android:fillAfter="true"
/>
</set>
ball_out.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_decelerate_interpolator">
<scale
android:fromXScale="0.623"
android:toXScale="0.623"
android:fromYScale="0.623"
android:toYScale="0.623"
/>
<translate
android:fromXDelta="130"
android:toXDelta="330"
android:duration="2000"
android:startOffset="0"
/>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_decelerate_interpolator">
<translate
android:fromYDelta="220"
android:toYDelta="370"
android:duration="1900"
android:startOffset="100"
/>
</set>
</set>
I originally had everything in one long animation, but wanted to split the animations up to be able to stop and continue at a given time in the code. Doing so, I realized that the position of the image was reset back to the starting position when the animation was finished and this of course gave me weird results when splitting up the animations.
I tried using fillAfter/fillBefore, which is described as applying transformations after/before the animation process, but they doesnt seem to do anything to the image. It still resets back to the starter position.
Any help or suggestions on how to do this is appriciated. Thanks.
Upvotes: 4
Views: 5360
Reputation: 1837
Hacky, but you can get the final transformation and apply that to your ImageView
. I haven't tested actually applying the returned Matrix, but the reflection code works nicely.
@Override
public void onAnimationEnd(Animation animation) {
Transformation t = new Transformation();
final float interpolatedTime = animation.getInterpolator().getInterpolation(animation.getDuration());
Class params[] = {Float.TYPE, Transformation.class};
try {
Method m = mAnimationYouWantToGetFinalTransformationFrom.getClass().getDeclaredMethod("applyTransformation", params);
m.setAccessible(true);
m.invoke(mAnimationYouWantToGetFinalTransformationFrom, interpolatedTime, t);
// update object to this final transformation matrix
// For Example: mObjectMatrix = t.getMatrix();
// run your next animation
} // Necessary Catch blocks
This issue can be avoided for projects using 3.0 and after. Use a ValueAnimator - the animation updates the actual object (in this case, your ballImage) properties instead of animating a representation of your object (which is what the 'old' Translate and Scale animations do).
Upvotes: 2
Reputation: 1463
You should use an AnimationSet for concatenating animation programatically in android. It should look something like this
AnimationSet anim = new AnimationSet(false);
final Animation ballInAnimation = AnimationUtils.loadAnimation(this,
R.anim.ball_in);
ballInAnimation.setFillBefore(true);
final Animation ballShiftAnimation = AnimationUtils.loadAnimation(this,R.anim.ball_shift);
ballShiftAnimation.setStartOffset(ballInAnimation.getDuration());
final Animation ballOutAnimation = AnimationUtils.loadAnimation(this,R.anim.ball_out);
ballOutAnimation.setStartOffset(ballInAnimation.getDuration()+ ballShiftAnimation.getDuration());
anim.addAnimation(ballInAnimation);
anim.addAnimation(ballShiftAnimation);
anim.addAnimation(ballOutAnimation);
anim.setFillAfter(true);
ballImage.startAnimation(anim);
This should work given your TweenAnimations defined in the XML are properly connected. Notice that this will only work VISUALLY, if you need the view to be clickable, you should use ValueAnimator instead of the Animation
Upvotes: 4
Reputation: 39605
This might not be the most elegant solution and it might not work either but is is worth a try.
Before you call the next animation in the onAnimationEnd()
method try to set the ImageViews new position to the position where the animation ended using the setFrame() method. This might not work as I haven't tested it myself but give it a try and tell me the outcome.
Upvotes: 0