Search code examples
androidanimationzoomingtimertask

Smoothly change animation duration during animating


I have two things.

The first is a looping scale animation doing a kind of permanent zoom in / zoom out.

The second thing is a TimerTask that set the duration of this scale animation every 20 seconds.

The problem is that sometimes there is kind of "jump" in the animation when the setDuration() occurs.

First i put this setDuration() in the TimerTask, then I just tried to put a flag in the TimerTask and changed the duration in onAnimationEnd(), it didn't work neither, same problem. In he code below I use this flag technic.

In case it's not enough clear the goal of all this is to have an "infinite" zoom in / out of a drawable circle, the zoom in / out speed decreasing in time. It actually works but it's not smooth, as said above.

Is there a way to do this smoothly ?

The TimeTask that sets the flag "changeDurationFlag"

private void setRegularRythmeDecrease() {

    final Handler handler = new Handler();
    Timer timer = new Timer();

    TimerTask task = new TimerTask() {
        @Override
        public void run() {
            handler.post(new Runnable() {
                public void run() {
                    try {
                        if (elapsedTime > sessionLengthInSec) {
                            circle.clearAnimation();
                        }
                        zoomDuration = zoomDuration + (toDecreaseEveryUpdate / 2);
                        changeDurationFlag = true;


                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    };
    timer.schedule(task, 0, BREATH_RYTHME_UPDATE_INTERVAL_IN_SECONDS*1000);
}

The ScaleAnimation I use to zoom in and out

public Animation scaleAnimation(View v, float startScale, float endScale, long duration) {
    Animation anim = new ScaleAnimation(
            startScale, endScale,
            startScale, endScale,
            Animation.RELATIVE_TO_SELF, 0.5f,
            Animation.RELATIVE_TO_SELF, 0.5f);
    anim.setFillAfter(true);
    anim.setDuration(duration);
    return anim;
}

The Animation listeners where the duration is set

    zoomDuration = ZOOM_DURATION_START;
    animZoomIn = scaleAnimation(circle, 1f, ZOOM_FACTOR,zoomDuration);
    animZoomOut = scaleAnimation(circle, ZOOM_FACTOR, 1f,zoomDuration);
    animZoomIn.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        @Override
        public void onAnimationEnd(Animation animation) {
            // If the flag is true (modified in the TimerTask) I set the Duration to decrease the speed
            // it's where the not smoothly thing happens
            if(changeDurationFlag) { 
                Log.d("beat ","Set breath to " + String.valueOf(zoomDuration * 2d));
                animZoomIn.setDuration(zoomDuration);
                animZoomOut.setDuration(zoomDuration);
                changeDurationFlag = false;
            }
            circle.startAnimation(animZoomOut);
        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
    });
    animZoomOut.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        @Override
        public void onAnimationEnd(Animation animation) {

            circle.startAnimation(animZoomIn);

            currentDateTime = Calendar.getInstance().getTime();
            elapsedTime = currentDateTime.getTime() - startDateTime.getTime();

            long elapsedTimeInSeconds = TimeUnit.MILLISECONDS.toSeconds(elapsedTime);

            beatCount++;
        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
    });

Solution

  • I had a problem with the value update of the variables elapsedTime and sessionLengthInSec. It means that sometimes (elapsedTime > sessionLengthInSec) was true when it shouldn't and a circle.clearAnimation() happened... so sure it produced a jump !

    Sure the jump can still happen if the duration change is too much big, but it's kind of normal since the speed would increase rapidly. In my code it was not the case because the speed increasing is less than 200ms so hardly viewable with eyes/

    Sorry for this, actually this code works perfectly...