1

I have a circle that I want to bounce, so it would expand in width, and collapse in height, then the reverse and the same for a few times. That all works with a few ScaleAnimations in a row. The problem is, that I want pivotY to be the bottom of the view. In this case every time a new animation starts it'll reset the pivot point to the center. Here's my code:

    bounceAnimationPartOne = new ScaleAnimation(1.0f, 1.0f, 1.62f, 0.62f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 1.0f);
    bounceAnimationPartOne.setDuration(45);
    bounceAnimationPartOne.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
        }

        @Override
        public void onAnimationEnd(Animation animation) {
            view.startAnimation(bounceAnimationPartTwo);
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
        }
    });

    bounceAnimationPartTwo = new ScaleAnimation(1.62f, 0.62f, 0.76f, 1.3f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 1.0f);
    bounceAnimationPartTwo.setDuration(90);
    bounceAnimationPartTwo.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        @Override
        public void onAnimationEnd(Animation animation) {
            view.startAnimation(bounceAnimationPartThree);
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
        }
    });

    bounceAnimationPartThree = new ScaleAnimation(0.76f, 1.3f, 1.23f, 0.81f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 1.0f);
    bounceAnimationPartThree.setDuration(105);
    bounceAnimationPartThree.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        @Override
        public void onAnimationEnd(Animation animation) {
            view.startAnimation(bounceAnimationPartFour);
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
        }
    });

    bounceAnimationPartFour = new ScaleAnimation(1.23f, 0.81f, 1.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 1.0f);
    bounceAnimationPartFour.setDuration(60);
Maria Neumayer
  • 3,337
  • 3
  • 27
  • 44

2 Answers2

1

I ended up writing my own custom Animation that basically does 4 scale animations in a row:

public class BounceAnimation extends Animation {
    private final List<Float> expansionValuesX;
    private final List<Float> expansionValuesY;
    private final List<Float> timing;

    private int currentTimingIndex;
    private float currentTimingSum;

    private float pivotX;
    private float pivotY;

    public BounceAnimation(List<Float> expansionValuesX, List<Float> expansionValuesY, List<Float> timing, int duration) {
        this.expansionValuesX = expansionValuesX;
        this.expansionValuesY = expansionValuesY;
        this.timing = timing;

        setDuration(duration);
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        float sx = 1.0f;
        float sy = 1.0f;

        if (currentTimingIndex < timing.size() - 1 && interpolatedTime >= currentTimingSum + timing.get(currentTimingIndex)) {
            currentTimingSum += timing.get(currentTimingIndex);
            currentTimingIndex++;
        }

        float currentFromX = expansionValuesX.get(currentTimingIndex);
        float currentFromY = expansionValuesY.get(currentTimingIndex);
        float currentToX = expansionValuesX.get(currentTimingIndex + 1);
        float currentToY = expansionValuesY.get(currentTimingIndex + 1);

        float currentInterpolatedTime = (interpolatedTime - currentTimingSum) / timing.get(currentTimingIndex);

        if (currentFromX != 1.0f || currentToX != 1.0f) {
            sx = currentFromX + ((currentToX - currentFromX) * currentInterpolatedTime);
        }
        if (currentFromY != 1.0f || currentToY != 1.0f) {
            sy = currentFromY + ((currentToY - currentFromY) * currentInterpolatedTime);
        }

        if (pivotX == 0 && pivotY == 0) {
            t.getMatrix().setScale(sx, sy);
        } else {
            t.getMatrix().setScale(sx, sy, pivotX, pivotY);
        }
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);

        pivotX = resolveSize(Animation.RELATIVE_TO_SELF, 0.5f, width, parentWidth);
        pivotY = resolveSize(Animation.RELATIVE_TO_SELF, 1.0f, height, parentHeight);

        currentTimingIndex = 0;
        currentTimingSum = 0;
    }

}
Maria Neumayer
  • 3,337
  • 3
  • 27
  • 44
0

Just because you animate something doesn't mean you have changed it (see previous discussion).

You may want to modify the onAnimationEnd() method to make the effect of your animations permanent before starting another animation.

Alternatively, use an AnimationSet and set the startOffset for the second and third animations in the set. Or, even easier, use a AnimatorSet.Builder.

Community
  • 1
  • 1
Brian Attwell
  • 9,239
  • 2
  • 31
  • 26
  • Yes, thanks I understand that. But I was hoping there was a different way of animating things in a row. – Maria Neumayer Feb 02 '13 at 02:51
  • I think what you are looking for is an AnimationSet? Second and third animations will need startOffset. http://developer.android.com/reference/android/view/animation/AnimationSet.html – Brian Attwell Feb 02 '13 at 02:53
  • 1
    AnimationSet was the first thing I've tried, but it has the same effect. It has to work on API level 7+, so AnimatorSet.Builder is not an option. I know there's NineOldAndroid, but ideally I don't want to include another library – Maria Neumayer Feb 02 '13 at 03:17
  • That is good news. I figured it would only support 8+. Don't spend your time supporting API < 7! Only 0.2% of users are on API < 7 (source: developer.android.com/about/dashboards/index.html ). And they probably have phones so shitty that they don't want to buy nice software. Moreover, AnimationSet is supported on all APIs >= 1 (source: http://developer.android.com/reference/android/view/animation/AnimationSet.html ). I wrote up a sample app a minute ago using AnimationSet without AnimationSet.Builder. It was a pleasant experience. – Brian Attwell Feb 02 '13 at 03:29
  • What do you mean when you say "AnimationSet ... has the same effect"? You're trying to figure out a way to chain animations toghether, right? AnimationSet does that. – Brian Attwell Feb 02 '13 at 04:47
  • I found a solution to the problem (see answer) – Maria Neumayer Feb 03 '13 at 07:28