Java – Apply transforms after animating objects on Android

Apply transforms after animating objects on Android… here is a solution to the problem.

Apply transforms after animating objects on Android

I’m trying to animate a ball image coming into the screen, moving position within the screen and back off-screen. I want to do this in the form of 3 animations; ball_in, ball_shift, and ball_out, and the ability to decide when to move from one animation to another.

This is the code I get so far;

Master .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>

Primary 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

initially put everything in one long animation, but I wanted to split the animation to be able to stop and continue at a given time in the code. In doing so, I realized that the position of the image was reset back to the starting position when the animation was complete, which of course gave me strange results when splitting the animation.

I tried using fillAfter/fillBefore, which is described as applying transforms after/before the animation process, but they don’t seem to do anything to the image. It will still be reset back to the starting position.

Any help or advice on how to do this applies. Thank you.

Solution

You should use AnimationSet for android is connected programmatically.
It should look 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);

If the TweenAnimations you defined in the XML are connected correctly, this should work.
Note that this will only work visually, and if you need a clickable View, you should use ValueAnimator instead of animation

Related Problems and Solutions