android – How to animate a View's translation-ThrowExceptions

Exception or error:

At the first click of a button, I want to slide a View along the x-axis (by 200 pixels to the right let’s say). And on the second press of the button, I want to slide the View back along the x-axis to its original position.

The View.setTranslationX(float) method jumps the View to the target horizontal locations with calls myView.setTranslationX(200); and myView.setTranslationX(0); respectively. Anyone know how I can slide the View to the target horizontal locations instead?

Note 1: A TranslateAnimation is no good since it doesn’t actually move
the View but only presents the illusion of it moving.

Note 2: I didn’t realise at the time of posing the question that the setTranslationX(float) and setTranslationY(float) methods were introduced as of API Level 11. If you’re targeting Honeycomb (API Level 11) upwards, then Gautam K’s answer will suffice. Otherwise, see my answer for a suggested solution.

How to solve:

Try looking into ObjectAnimator and its super class Value Animator

you can do something like this
ObjectAnimator anim = ObjectAnimator.ofFloat(this, "translationX", 0,200);
and then
anim.start();

Use a boolean value and toggle it with 200,0 in the object animator to slide back

PS: you can use setDuration method to set how long the animation should take to complete

Edit :

Try looking at the support library which provides backward compatibility.

Edit

As @AdilHussain pointed out there is a library called nineoldandroids which can be used for the same purpose on older androids.

###

This one’s had me stumped for a fair few days (getting it to work pre- Ice Cream Sandwich) but I think I’ve finally got there! (thanks to Gautam K and Mike Israel for the leads) What I did in the end was to extend my View (a FrameLayout) to start the translate right/left animations as required and to listen for the end of the animations in order to relocate my FrameLayout right/left as appropriate, as follows:

public class SlidingFrameLayout extends FrameLayout
{
  private final int durationMilliseconds = 1000;
  private final int displacementPixels = 200;

  private boolean isInOriginalPosition = true;
  private boolean isSliding = false;

  public SlidingFrameLayout(Context context)
  {
    super(context);
  }

  public SlidingFrameLayout(Context context, AttributeSet attrs)
  {
    super(context, attrs);
  }

  public SlidingFrameLayout(Context context, AttributeSet attrs, int defStyle)
  {
    super(context, attrs, defStyle);
  }

  @Override
  protected void onAnimationEnd()
  {
    super.onAnimationEnd();

    if (isInOriginalPosition)
      offsetLeftAndRight(displacementPixels);
    else
      offsetLeftAndRight(-displacementPixels);

    isSliding = false;
    isInOriginalPosition = !isInOriginalPosition;
  }

  @Override
  protected void onLayout(boolean changed, int left, int top, int right, int bottom)
  {
    super.onLayout(changed, left, top, right, bottom);

    // need this since otherwise this View jumps back to its original position
    // ignoring its displacement
    // when (re-)doing layout, e.g. when a fragment transaction is committed
    if (changed && !isInOriginalPosition)
      offsetLeftAndRight(displacementPixels);
  }

  public void toggleSlide()
  {
    // check whether frame layout is already sliding
    if (isSliding)
      return; // ignore request to slide

    if (isInOriginalPosition)
      startAnimation(new SlideRightAnimation());
    else
      startAnimation(new SlideLeftAnimation());

    isSliding = true;
  }

  private class SlideRightAnimation extends TranslateAnimation
  {
    public SlideRightAnimation()
    {
      super(
          Animation.ABSOLUTE, 0,
          Animation.ABSOLUTE, displacementPixels,
          Animation.ABSOLUTE, 0,
          Animation.ABSOLUTE, 0);

      setDuration(durationMilliseconds);
      setFillAfter(false);
    }
  }

  private class SlideLeftAnimation extends TranslateAnimation
  {
    public SlideLeftAnimation()
    {
      super(
          Animation.ABSOLUTE, 0,
          Animation.ABSOLUTE, -displacementPixels,
          Animation.ABSOLUTE, 0,
          Animation.ABSOLUTE, 0);

      setDuration(durationMilliseconds);
      setFillAfter(false);
    }
  }
}

And, lastly, to slide the SlidingFrameLayout right/left, all you’ve got to do is call the SlidingFrameLayout.toggleSlide() method. Of course you can tweak this SlidingFrameLayout for your purposes to slide a greater number of pixels, to slide for longer etc, but this should be sufficient to get you started 🙂

###

I had a similar issue, TranslateAnimation does actually move the view if you call setFillAfter now (android bug). I had to do something similar so I said, hey lets use an animation listener and then just move everything to the correct location. Unfortunately there is a bug on animation listeners as well (stackoverflow solution). So I created my own layout class according to the solution in the stackoverflow solution and I was good to go 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *