13

I was playing around with the fab in the support design library when I ran inti this issue. I replaced the onCreate method in the default Blank Activity template in Android Studio, this is what it looks like:

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.animation.TranslateAnimation;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        final FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                TranslateAnimation anim = new TranslateAnimation(0, -500, 0, -500);
                anim.setDuration(1000);
                anim.setFillEnabled(true);
                anim.setFillAfter(true);
                fab.startAnimation(anim);
            }
        });
        fab.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {
                TranslateAnimation anim = new TranslateAnimation(0, -500, 0, -500);
                anim.setDuration(1000);
                anim.setFillEnabled(true);
                anim.setFillAfter(true);
                fab.startAnimation(anim);
                return true;
            }
        });
    }
}

So basically, I added an onClickListener and an onLongClickListener that translate the fab by 500idks, but the problem is that it doesn't work like it's supposed to.

When I click on it normally nothing happens, which is weird to start with. Here's a video of it happening.

When I longPress on it, it animates like I should, but only if I keep pressing, and whenever I lift my finger it goes back to the original position regardless of whether the animation is complete or not even though I set setFillEnabled(true) and setFillAfter(true).

Here are videos of what happens when I lift my finger and when I leave my finger on the screen till the end and everything.

Animation

Why is this happening?

Olumide
  • 738
  • 12
  • 30
  • I think you should declare `FloatingActionButton fab` is a global variables – Mr Neo Jan 30 '16 at 01:45
  • @MrNeo it is didn't make a difference – Olumide Jan 30 '16 at 01:49
  • 1
    I tried this on Nexus 4, on version 5.1.1. It works as you expected and doesn't have the problems you are seeing on your setup. – Lewis McGeary Feb 02 '16 at 15:24
  • 1
    @lewis I tested it on 4.4.4, which falls back to a different implementation according to the source. So I guess this solves a bit of the mystery. Thanks for the comment – Olumide Feb 02 '16 at 17:41

5 Answers5

6

I don't know why you get this animation issue, but it looks like a bug. I checked your code and it works on my Android 6.0, but it doesn't work on Android Emulator with Android 4.4 on board (but my issue a little bit different then yours).

So my assumption it's a bug, because TranslateAnimation had (and maybe still has) some bugs like this one, two.

And my suggestion how you can avoid it is next. Use ViewPropertyAnimator to animate your views. And your code in this case should look like:

    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            fab.animate()
                    .translationX(-500)
                    .translationY(-500)
                    .setDuration(1000)
                    .start();
        }
    });
    fab.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View view) {
            fab.animate()
                    .translationX(-500)
                    .translationY(-500)
                    .setDuration(1000)
                    .start();
            return true;
        }
    });

I checked it on Android Emulator with Android 4.3, 4.4, 5.0, 6.0 and it works fine.

Update

Found solution for you. So you can use ViewPropertyAnimatorCompat from support library and your code would be similar to:

fab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
            ViewCompat.animate(fab)
                    .translationX(-500)
                    .translationY(-500)
                    .setDuration(1000)
                    .start();
    }
});
fab.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View view) {
            ViewCompat.animate(fab)
                    .translationX(-500)
                    .translationY(-500)
                    .setDuration(1000)
                    .start();
        return true;
    }
});
Igor Tyulkanov
  • 5,327
  • 2
  • 28
  • 48
  • Yeah ViewPropertyAnimator works on my device too, but I wanted something that worked with api 11 and ViewPropertyAnimator was introduced in 12. I also looks like you may be right about the bug too – Olumide Feb 03 '16 at 20:37
  • @Olumide, in that case you can try to use this library https://github.com/JakeWharton/NineOldAndroids – Igor Tyulkanov Feb 04 '16 at 01:57
  • @Olumide, found solution for you, see my updated answer – Igor Tyulkanov Feb 04 '16 at 09:22
  • ViewCompat would have been nice but the [documentation](http://developer.android.com/reference/android/support/v4/view/ViewCompat.html#animate(android.view.View)) says "Prior to API 14, this method will do nothing." – Olumide Feb 04 '16 at 19:13
  • What about `ViewPropertyAnimator` from NineOldAndroids as I said? `com.nineoldandroids.view.ViewPropertyAnimator.animate(fab).translationX(-500).translationY(-500).setDuration(1000).start();` Checked it, works fine for FAB – Igor Tyulkanov Feb 05 '16 at 01:40
3

Update: it's now suppose to be fixed in support lib 24.2.0 following the bug I've opened: https://code.google.com/p/android/issues/detail?id=215043

==============

For those of us that not lucky enough to just replace their animation with a ViewPropertyAnimation like me:

This bug happens because of a bug in the support implementation of the FloatingActionButton, specific in the FloatingActionButtonEclairMr1 class, where setting animation to all view states, so when clicking the view there's a FloatingActionButtonEclairMr1.ElevateToTranslationZAnimation animation that is fired, so your animation is cleared from the view.

The simplest solution that I've find is just starting your animation with some delay, NOT with startOffset (because it still going to be override by the pressing animation) but with calling the animation with delay (I'm using 100, but also check with 60 and it worked. 20 is not enough):

    final FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            //Probably want to do it just for pre Lolipop
            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    TranslateAnimation anim = new TranslateAnimation(0, -500, 0, -500);
                    anim.setDuration(1000);
                    anim.setFillEnabled(true);
                    anim.setFillAfter(true);
                    fab.startAnimation(anim);
                }
            }, 100);
        }
    });
    fab.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View view) {
            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    TranslateAnimation anim = new TranslateAnimation(0, -500, 0, -500);
                    anim.setDuration(1000);
                    anim.setFillEnabled(true);
                    anim.setFillAfter(true);
                    fab.startAnimation(anim);
                }
            }, 100);
        }
    });
shem
  • 4,368
  • 2
  • 28
  • 42
2

I think you have to keep anim object as a class level variable, onLongClick() and onClick() gets called in overlapped fashion in many cases. Since, you have different anim objects, you end up accessing same fab from two anim objects.

Keep anim outside and post your observation please.

and try removing either onLongClick() or onClick() methods. if possible add log in those two methods in order to understand call sequence.

I will be waiting for your observations.

Karthik Kumar
  • 1,165
  • 1
  • 9
  • 29
1

Maybe this concerns to your problem: SO-Thread

I am using a AnimatorListener to set the position of a view after a finished animation.

.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {

        }

        @Override
        public void onAnimationEnd(Animator animation) {
            // set Position
        }

        @Override
        public void onAnimationCancel(Animator animation) {

        }

        @Override
        public void onAnimationRepeat(Animator animation) {

        }
    });

I only see a excerpt of your code. For your problem with the onClickListener I would check if you have set android:clickable="false" inside your xml or if you have implemented another OnClickListener.

Community
  • 1
  • 1
skymedium
  • 723
  • 5
  • 24
  • The link you provided was insightful, but it however doesn't explain why the animation as soon as I lift my finger. I also updated the code to include everything – Olumide Jan 31 '16 at 23:35
1

You need to use ViewPropertyAnimator to make this work. The animation does not actually move the view itself, just a bitmap representation of the view, as described here.

Community
  • 1
  • 1
Piyush
  • 1,622
  • 1
  • 12
  • 28