Android: Animation Position Resets After Complete

Viewed 86566

I'm using an xml defined animation to slide a view off the screen. The problem is, as soon as the animation completes it resets to its original position. I need to know how to fix this. Here's the xml:

<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_interpolator">
   <translate android:fromXDelta="0" android:toXDelta="-100%p" android:duration="500"/></set>

Here's the Java that I use to call it:

    homeScrn = (View)findViewById(R.id.homescreen);
    slideLeftOut = AnimationUtils.loadAnimation(this, R.anim.slide_left_out);

    //Set Click Listeners For Menu
    btnHelp.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            LayoutInflater.from(getApplicationContext()).inflate(R.layout.help, (ViewGroup)findViewById(R.id.subpage), true);
            homeScrn.startAnimation(slideLeftOut);
        }
    });

So basically what happens is I inflate a view underneath one. Then I animate the view on top off to the left. As soon as it gets off screen and the animation is finished it resets its position back.

10 Answers

fillAfter = true will do the job to transform view to new animation positon.

rotateAnimation.fillAfter = true;

If anybody interested to move arrow_up & arrow_down animations for a recycle view expands/collapse behavior.

  1. Initial state: Collapse
  2. call the method with a child visibility flag(View.VISIBLE/View.GONE).

Below is code belongs to animations.

fun setArrowImage(imageView: ImageView, childVisibility: Int) {

    val angleRange = if (childVisibility == View.VISIBLE) Pair(0F, 180F) else 
    Pair(100f, 0F)

    val rotateAnimation = RotateAnimation(
        angleRange.first, angleRange.second,
        Animation.RELATIVE_TO_SELF, 0.5f,
        Animation.RELATIVE_TO_SELF, 0.5f
    )
    rotateAnimation.duration = 300
    rotateAnimation.fillAfter = true;

    imageView.startAnimation(rotateAnimation)
}

Use helper methods below to easily animate your view. Then you can animate and reset after completion like this:

// Animate the view:

fly(
  view1,
  (float) 0,
  (float) 0,
  (float) 0,
  (float) 1000,
  250,
  null,
  null,
  () -> {

    // Return the view to initial position on animation end:  

    fly(
      view1,
      (float) 0,
      (float) 0,
      (float) 0,
      (float) 0,
      0);

    return null;
  });

Helper methods:

/**
 * Translation of a view.
 */
public static void fly(
  View view,
  float fromXDelta,
  float toXDelta,
  float fromYDelta,
  float toYDelta,
  int duration) {

  fly(
    view,
    fromXDelta,
    toXDelta,
    fromYDelta,
    toYDelta,
    duration,
    null,
    null,
    null);
}

/**
 * Translation of a view with handlers.
 *
 * @param view       A view to animate.
 * @param fromXDelta Amount to shift by X axis for start position.
 * @param toXDelta   Amount to shift by X axis for end position.
 * @param fromYDelta Amount to shift by Y axis for start position.
 * @param toYDelta   Amount to shift by Y axis for end position.
 * @param duration   Animation duration.
 * @param start      On animation start. Otherwise NULL.
 * @param repeat     On animation repeat. Otherwise NULL.
 * @param end        On animation end. Otherwise NULL.
 */
public static void fly(
  View view,
  float fromXDelta,
  float toXDelta,
  float fromYDelta,
  float toYDelta,
  int duration,
  Callable start,
  Callable repeat,
  Callable end) {

  Animation animation;

  animation =
    new TranslateAnimation(
      fromXDelta,
      toXDelta,
      fromYDelta,
      toYDelta);

  animation.setDuration(
    duration);

  animation.setInterpolator(
    new DecelerateInterpolator());

  animation.setFillAfter(true);

  view.startAnimation(
    animation);

  animation.setAnimationListener(new AnimationListener() {

    @Override
    public void onAnimationStart(Animation animation) {

      if (start != null) {
        try {

          start.call();

        } catch (Exception e) {
          e.printStackTrace();
        }
      }

    }

    @Override
    public void onAnimationEnd(Animation animation) {

      if (end != null) {
        try {

          end.call();

        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }

    @Override
    public void onAnimationRepeat(
      Animation animation) {

      if (repeat != null) {
        try {

          repeat.call();

        } catch (Exception e) {
          e.printStackTrace();
        }
      }  
    }
  });
}

Nothing from answers worked with me; although @Muhammad Babar answer inspired me to get a solution:

He mentioned that we can layout the view to the new position upon animation end:

public void onAnimationEnd(Animation animation) {
   someView.layout(150, 0, someView.getWidth() + 150, someView.getHeight());
}

Although this didn't work with me instead; I had to do that in a Handler with delayed Runnable using a delay value that is slightly less than the animation duration.

So, in my case the animation duration is 500 msec, and I used a handler on 450 mesec, so it gets triggered just before the animation ends by 50 msec.

Handler().postDelayed({
    someView.layout(150, 0, someView.width + 150, someView.hight)
    someView.requestLayout()
    someView.forceLayout()
}, 450)
Related