Maria Neumayer
Maria Neumayer

Reputation: 3357

Android circle bouncing Animation

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);

Upvotes: 1

Views: 1290

Answers (2)

Maria Neumayer
Maria Neumayer

Reputation: 3357

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;
    }

}

Upvotes: 1

Brian Attwell
Brian Attwell

Reputation: 9299

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.

Upvotes: 0

Related Questions