Avilan
Avilan

Reputation: 41

Applying transformation after animating an object on android

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

Answers (3)

c2knaps
c2knaps

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

apenasVB
apenasVB

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

Octavian Helm
Octavian Helm

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

Related Questions