浮动操作按钮动画问题

13

我在使用支持设计库中的fab时遇到了问题。我替换了Android Studio中默认的空白活动模板中的onCreate方法,如下所示:

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

所以基本上,我添加了一个 onClickListener 和一个 onLongClickListener,将 fab 移动了 500idks,但问题是它的工作方式不像应该的那样。

当我正常点击它时,什么也不会发生,这本身就很奇怪。这里有一个视频展示了它的情况。

当我长按它时,它会像应该的那样进行动画,但只有在我持续按住它时才会动画,而且无论动画是否完成,每当我松开手指时,它都会回到原始位置,尽管我设置了 setFillEnabled(true)setFillAfter(true)

这里有一些视频,展示了当我 抬起 手指时和当我 离开 屏幕直到结束以及 全部 的情况。

Animation

为什么会发生这种情况?

我认为你应该将 FloatingActionButton fab 声明为全局变量。 - Neo
@MrNeo 没有任何区别。 - Olumide
1
我在Nexus 4上的5.1.1版本尝试了这个,它按照你的期望工作,并且没有你在设置中看到的问题。 - Lewis McGeary
1
@lewis 我在4.4.4上进行了测试,根据源代码,它会回退到不同的实现。所以我猜这解决了一些谜团。感谢您的评论。 - Olumide
5个回答

6

我不知道你为什么会遇到这个动画问题,但它看起来像是一个bug。我检查了你的代码,在我的安卓6.0上运行正常,但在安卓4.4的模拟器上无法工作(但我的问题与你的有点不同)。

所以我的假设是这是一个bug,因为TranslateAnimation曾经有(也许现在还有)一些类似于这个这个的bug。

我的建议是你可以使用ViewPropertyAnimator来动画化你的视图,以避免这个问题。在这种情况下,你的代码应该像这样:

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

我已经在Android模拟器上测试了Android 4.3、4.4、5.0和6.0,并且它可以正常工作。
更新
我为您找到了解决方案。因此,您可以使用来自支持库的ViewPropertyAnimatorCompat,您的代码应类似于:
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;
    }
});

是的,ViewPropertyAnimator 在我的设备上也可以工作,但我想要一个能够在 API 11 上工作的东西,而 ViewPropertyAnimator 是在 12 中引入的。看起来你关于这个 bug 的说法也是正确的。 - Olumide
@Olumide,如果是这样的话,您可以尝试使用这个库https://github.com/JakeWharton/NineOldAndroids。 - Igor Tyulkanov
@Olumide,我为你找到了解决方案,请查看我的更新答案。 - Igor Tyulkanov
ViewCompat本来是个不错的选择,但是文档中写道:“在API 14之前,该方法将不起任何作用。” - Olumide
那么关于我之前提到的NineOldAndroids中的ViewPropertyAnimator呢?com.nineoldandroids.view.ViewPropertyAnimator.animate(fab).translationX(-500).translationY(-500).setDuration(1000).start(); 我已经检查过了,对于FAB运行良好。 - Igor Tyulkanov

3
更新:根据我提出的错误,它现在应该在支持库24.2.0中得到修复:https://code.google.com/p/android/issues/detail?id=215043 对于我们这些不够幸运可以像我一样用替换他们的动画的人来说:
这个bug是由FloatingActionButton的支持实现中的一个bug引起的,具体表现为在FloatingActionButtonEclairMr1类中设置所有视图状态的动画,所以当点击视图时,会触发一个FloatingActionButtonEclairMr1.ElevateToTranslationZAnimation动画,从而清除了您的动画。
我发现最简单的解决方案就是延迟一段时间开始您的动画,而不是使用startOffset(因为它仍然会被按下的动画覆盖),而是通过调用带有延迟的动画(我使用100,但也尝试了60,它也可以正常工作。20不够)。
    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);
        }
    });

2

我认为您需要将anim对象作为类级别变量保留,因为在许多情况下,onLongClick()和onClick()方法会以重叠的方式调用。由于您有不同的anim对象,您最终会从两个anim对象中访问相同的fab。

请将anim对象放在外部并发布您的观察结果。

尝试删除onLongClick()或onClick()方法之一。如果可能,请在这两种方法中添加日志,以便了解调用顺序。

我将等待您的观察结果。


1

也许这与您的问题有关:SO-Thread

我正在使用AnimatorListener在动画完成后设置视图的位置。

.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) {

        }
    });

我只看到了你的代码摘录。针对你在 onClickListener 上遇到的问题,我建议检查一下你是否在 xml 中设置了 android:clickable="false",或者是否实现了另一个 OnClickListener。

您提供的链接很有见地,但它并没有解释为什么动画会在我抬起手指时立即停止。我还更新了代码,包括所有内容。 - Olumide

1
你需要使用 ViewPropertyAnimator 来实现这个功能。这个动画并不会移动视图本身,只是移动视图的位图表示,详见 这里

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接