Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Androids ObjectAnimator.ofFloat doesn't work properly

I've used ObjectAnimator.ofFloat in an Android App which doesn't work on every device the same way.

MainActivity (extends Activity):

Button button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        startAnimation();
    }
});


public void startAnimation() {
    ImageView aniView = (ImageView) findViewById(R.id.imageView1);
    ObjectAnimator fadeOut = ObjectAnimator.ofFloat(aniView, "alpha", 0f);
    fadeOut.setDuration(2000);

    ObjectAnimator mover = ObjectAnimator.ofFloat(aniView, "translationX", -500f, 0f);
    mover.setInterpolator(new TimeInterpolator() {
        @Override
        public float getInterpolation(float input) {
            Log.v("MainActivity", "getInterpolation() " + String.format("%.4f", input));
            return input;
        }
    });
    mover.setDuration(2000);

    ObjectAnimator fadeIn = ObjectAnimator.ofFloat(aniView, "alpha", 0f, 1f);
    fadeIn.setDuration(2000);

    AnimatorSet animatorSet = new AnimatorSet();

    animatorSet.play(mover).with(fadeIn).after(fadeOut);
    animatorSet.start();
}

Samsung Galaxy S4 (Android 4.4.2):

    getInterpolation() 1,0000
    getInterpolation() 1,0000

Samsung Galaxy S5 (Android 4.4.2):

    getInterpolation() 0,0000
    getInterpolation() 0,0000
    getInterpolation() 0,0085
    getInterpolation() 0,0170
    getInterpolation() 0,0255
    ...
    ...
    getInterpolation() 0,9740
    getInterpolation() 0,9825
    getInterpolation() 0,9910
    getInterpolation() 0,9995
    getInterpolation() 1,0000

Has anyone an idea, why this doesn't work properly?

like image 617
Benjamin Stürmer Avatar asked Aug 26 '14 12:08

Benjamin Stürmer


2 Answers

Users can easily manipulate the scale value in Developer options or custom ROM providers. This could be a very tricky problem if you don't know what caused it in the first place.


Solution

You can just set an animation duration scale to 1 or any other pleasing value programmatically via Reflection API's capability. Thus, this will behave the same all across Android devices for your app. Unfortunately, Android is not giving us a warning about it on its page and a solution choice rather than Reflection due to the function itself is restricted from public usage via @hide annotation.

For more about Android's API restriction, You could read this thread;

What does @hide mean in the Android source code?

In Java

try {
    ValueAnimator.class.getMethod("setDurationScale", float.class).invoke(null, 1f);
} catch (Throwable t) {
    Log.e(TAG, t.getMessage());
}

In Kotlin

// You could also surround this line with try-catch block like above in Java example
ValueAnimator::class.java.getMethod("setDurationScale", Float::class.javaPrimitiveType).invoke(null, 1f)

I believe, this solution is more solid and robust rather than making users set it in developer settings.

like image 71
Yekta Sarıoğlu Avatar answered Oct 26 '22 17:10

Yekta Sarıoğlu


On the Galaxy S4, under Developer Options, there is the option Animator duration scale. For some wild reason, this is off by default. After switching this to 1x, my animations on the S4 started to work perfectly. This may be what is causing your problem.

like image 27
Mike Baxter Avatar answered Oct 26 '22 18:10

Mike Baxter