QThompson
QThompson

Reputation: 1708

How do I make a smooth animation with ValueAnimator?

I am wanting to hide an extended fab when it is clicked using an Animation. I want to scale the button down from original height and width to 0/gone. It disappears in the corner but the animation is laggy in the middle.

    private fun animateHideScoreFab(){
        val animX = ValueAnimator.ofInt(editScoreFab.measuredWidth, 0).apply {
            duration = 1000
        }
        val animY = ValueAnimator.ofInt(editScoreFab.measuredHeight, 0).apply {
            duration = 1000
        }


        animX.addUpdateListener {
            val value = it.animatedValue as Int
            editScoreFab.layoutParams.width = value
            editScoreFab.requestLayout()
        }

        animY.addUpdateListener {
            val value = it.animatedValue as Int
            editScoreFab.layoutParams.height = value
        }

        AnimatorSet().apply {
            this.interpolator = AccelerateDecelerateInterpolator()
            play(animX).with(animY)
            start()
        }

    }

Result:

enter image description here

Upvotes: 0

Views: 2887

Answers (2)

Marcos Vasconcelos
Marcos Vasconcelos

Reputation: 18276

There's a scaleX and scaleY property in Views that you can interpolate from 1 to 0, this will give the effect of the View shrinking and not the container.

Second, for a scale animation work to the top if your parent layout params doesn't do for you, you have to set the pivot to the rightXtop corner with: view.pivotX = view.width; view.pivotY = 0

Also, if you using propertyListener and updating it yourself you can use only one ValueAnimator and do the calc yourself plus consider replacing editScoreFab.requestLayout() with editScoreFab.invalidate()

Upvotes: 0

Andrew
Andrew

Reputation: 10162

Using AccelerateDecelerateInterpolator https://developer.android.com/reference/android/view/animation/AccelerateDecelerateInterpolator says

An interpolator where the rate of change starts and ends slowly but accelerates through the middle.

So in the middle the rate of change is faster than the start which could make it look laggy

Try another Interpolator like LinearInterpolator https://developer.android.com/reference/android/view/animation/LinearInterpolator.html which has a constant rate of change.

Update For AccelerateDecelerateInterpolator if you look at the table in https://developer.android.com/guide/topics/graphics/prop-animation.html#interpolators between 400ms and 600ms the the value jumps 45.5% of the distance you and animating

The other factor of smoothness is not to use an Int but use a Float e.g. ValueAnimator.ofFloat so it has intermediate steps,

Update2

Re-laying out an item is expensive as it has to be measured and redrawn.

It should be faster and smoother just to scale the already drawn image as this is usually done by the GPU and thus faster and smoother. Also scaling a view takes a Float

example of scaling a Fab to top right onClick (Note using ObjectAnimator as it is simpler to implement)

Sorry in Java not Kotlin

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                AnimatorSet animationSet = new AnimatorSet();

                // Set point to scale around to top right
                view.setPivotY(0);
                view.setPivotX(view.getMeasuredWidth());

                ObjectAnimator scaleY = ObjectAnimator.ofFloat(view,"scaleY", 1f, 0f);
                scaleY.setDuration(1000);
                // Optional as AccelerateDecelerateInterpolator is the default
                scaleY.setInterpolator(new AccelerateDecelerateInterpolator());
                ObjectAnimator scaleX = ObjectAnimator.ofFloat(view,"scaleX", 1f, 0f);
                scaleX.setDuration(1000);
                // Optional as AccelerateDecelerateInterpolator is the default
                scaleX.setInterpolator(new AccelerateDecelerateInterpolator());
                animationSet.playTogether(scaleX, scaleY);
                animationSet.start();
            }
        });

Upvotes: 2

Related Questions