2

My TranslateAnimation works, but at the end of the animiation, it jumps back to the original location.

        LinearLayout rl = (LinearLayout) findViewById(R.id.navPanel);

          animation = new TranslateAnimation(
              Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
              Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 3.0f
          );
          animation.setDuration(500);

          rl.startAnimation(animation);

How can I make it stay at the end location?

Brad
  • 11,262
  • 8
  • 55
  • 74
  • [see this link I hope it will be work ][1] [1]: http://stackoverflow.com/questions/7948129/trying-to-move-a-button-to-another-point-on-the-screen/7977065#7977065 – VSC Nov 03 '11 at 05:29

4 Answers4

8

The old (pre-3.0) Animation API behaves a bit weird - when it's animating, it merely translates where the view is drawn, but doesn't actually move the view with respect to its parents.

In order to get the view to stay put when the animation is done, you can set an Animation.AnimationListener on your TranslateAnimation. In the onAnimationEnd() method of the listener, you move the view to its final resting place by manipulating the LayoutParams on the view.

mportuesisf
  • 5,587
  • 2
  • 33
  • 26
  • Interesting - another thing I'm noticing is that when it's animating, the *contents* of my LinearLayout seem to be clipped to the *original* position of the LinearLayout. (Even it I turn ClipChildren to false). Is this happening for the same reason? – Brad Oct 27 '11 at 16:49
  • Yup - all the Animation does is temporarily alter how/where the view is rendered. It doesn't actually modify any aspect of the view properties within the view hierarchy. – mportuesisf Oct 27 '11 at 17:03
  • 2
    Another IMPORTANT thing to mention is that there are some weird bugs in handling the end of animation, where the content can move around unexpectedly. This can be resolved either by calling clearAnimation on your object inside onAnimationEnd, or by subclassing the view, implementing the onAnimationEnd directly in the subclass. See: http://stackoverflow.com/questions/4750939/android-animation-is-not-finished-in-onanimationend/5641518#comment9690906_5641518 – Brad Oct 28 '11 at 17:36
8

use animation.setFillAfter(true) for your animation to stop it at the end of translation.

http://developer.android.com/reference/android/view/animation/Animation.html#setFillAfter(boolean)

Yashwanth Kumar
  • 28,931
  • 15
  • 65
  • 69
  • 4
    That *looked* like it worked, but like it says in the link, click event's are handled at the *original* locations afterwards. It's like the screen was painted at the proper locations, but the controls are still where they originally were. – Brad Oct 27 '11 at 17:17
  • @Brad indeed that seems to be the case – 2cupsOfTech Jul 12 '12 at 11:25
3

this same problem https://stackoverflow.com/a/6519233/1253065

use animation.setFillAfter(true) , animation.setFillEnabled(true)

Community
  • 1
  • 1
semih
  • 821
  • 8
  • 16
1

To avoid repetitive code, you can subclass the AnimatorListenerAdapter and create your own AnimatorListener class where you re-attach the view after the animation, then use it wherever needed instead of the default AnimatorListener.

The class:

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;

public class PersistViewAnimatorListener extends AnimatorListenerAdapter {

    private View view; // keep a reference to the view
    public PersistViewAnimatorListener(View view) {
        this.view = view;
    }

    @Override public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);

        // re-attach the view to its parent at its new location
        if (view == null) { return; } // defensive, the view may have been removed while it was animated, do nothing in this case

        ViewGroup parent = (ViewGroup) view.getParent(); // get the parent
        if (parent == null) { return; } // defensive
        int index = parent.indexOfChild(view); // get the index of the view
        parent.removeView(view); // remove the view

        if (parent.getClass().equals(RelativeLayout.class)) { // RELATIVE LAYOUT
            RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(view.getLayoutParams()); // add the view back at its index with new layout parameters
            layoutParams.setMargins(Math.round(view.getX()), Math.round(view.getY()), 0, 0); // left, top, right, bottom; round the float to int
            parent.addView(view, index, layoutParams);
        } else if (parent.getClass().equals(FrameLayout.class)) { // FRAME LAYOUT
            FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(view.getLayoutParams()); // the same for FrameLayout
            layoutParams.setMargins(Math.round(view.getX()), Math.round(view.getY()), 0, 0);
            parent.addView(view, index, layoutParams);
        } else { // currently no further layouts supported, implement these here
            throw new UnsupportedOperationException("PersistViewAnimatorListener is currently only supported where the parent is either RelativeLayout or FrameLayout.");
        }

        view.setTranslationX(0); view.setTranslationY(0); // reset translated values from the animation

    }
}

And how you use it:

view.animate().yBy(height).setListener(new PersistViewAnimatorListener(view)); // call your custom listener in .setListener() and pass in the view

This solution assumes you are using RelativeLayout or FrameLayout for the parent. Also, it just cares about the position, not size or other properties that can be animated as well.

Oliver Hausler
  • 4,900
  • 4
  • 35
  • 70