单个动画 - 多个视图

25

有没有一种方法可以同时动画多个视图?

我想要做的是转换动画:

我有5个TextView和4个彩色条(带有背景的简单RelativeLayout)。 在动画开始时,stips与TextViews堆叠在水平行中。 到最后,我希望所有TextView都堆叠在strip之间:

enter image description here

这是一个非常简单的绘图,但它展示了我想做的事情。 是否有使用动画实现此目的的方法,还是必须使用canvas动画?

4个回答

59

您可以使用ObjectAnimator来对多个视图进行动画处理,具体如下:

ArrayList<ObjectAnimator> arrayListObjectAnimators = new ArrayList<ObjectAnimator>(); //ArrayList of ObjectAnimators

ObjectAnimator animY = ObjectAnimator.ofFloat(view, "y", 100f);
arrayListObjectAnimators.add(animY);

ObjectAnimator animX = ObjectAnimator.ofFloat(view, "x", 0f);
arrayListObjectAnimators.add(animX);
...
ObjectAnimator[] objectAnimators = arrayListObjectAnimators.toArray(new ObjectAnimator[arrayListObjectAnimators.size()]);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(objectAnimators);
animSetXY.setDuration(1000);//1sec
animSetXY.start();

2
唯一的缺点是它是自版本11(蜂巢)以来的新功能。 - Matthew
3
使用NineOldAndroids库可以将API版本向后兼容至1.0(http://nineoldandroids.com/)。 - Tushar
3
这并不会同时使多个对象动起来,而是在同一个对象上同时运行多个动画。 - Renascienza
1
我下载了Tushar提到的NineOldAndroids库,本来想要使用它,但是发现它的自述文件中提到该库已经被弃用,所以我觉得应该在这里分享一下:“NineOldAndroids已经被弃用。不会有新的开发工作进行。现有版本将(当然)继续运行。新的应用程序应该使用minSdkVersion="14"或更高版本,这样就可以访问平台动画API。” - RestInPeace
只是补充一下..你也可以避免使用ArralyList,而只是使用playTogher(animY, animY1)作为例子。 - Codeversed

7

您可以使用 AnimationSet

AnimatorSet decSet2 = new AnimatorSet();
        decSet2.playTogether(
                ObjectAnimator.ofFloat(view, "x",dX),
                ObjectAnimator.ofFloat(view, "y",dY),
                ObjectAnimator.ofFloat(mTextCancel, "x",dX),
                ObjectAnimator.ofFloat(mTextCancel, "y", dY),
                ObjectAnimator.ofArgb(mBtnOne, "visibility", View.VISIBLE, View.GONE),
                );
        decSet2.setDuration(0);
        decSet2.start();

7
创建您的动画对象,然后在所有视图上同时使用startAnimation。因此,它应该类似于这样:
TranslateAnimation anim1;
TranslateAnimation anim2;
TranslateAnimation anim3;

// Setup the animation objects

public void startAnimations()
{
   //... collect view objects
   view1.startAnimation(anim1);
   view2.startAnimation(anim2);
   view3.startAnimation(anim3);
}

请注意,同时进行的动画越多,速度就会越慢。


1
这不会导致它们不同步吗(在这里不是必要的),特别是那些后启动的? - Matthew
1
并不是这样的。基本上当你在一个视图上使用startAnimation时,它会开始无效化自己,直到达到预期位置。当你同时在所有视图上调用它们时,它们将都调用invalidate(),然后在下一次绘制过程中,每个视图将在它们的下一帧中被绘制。由于你无论如何都在UI线程上调用所有这些操作,直到从该方法返回之前,所有动画都不会启动。注意:在Honeycomb之前的动画框架中,只会移动视图的可视部分。用户将无法点击它。 - DeeV
我使用anim1.setFillAfter(true)来应用动画,然后通过使用布局参数来实际移动视图?(我应该尝试一下,但现在已经很晚了 :)) - Matthew
通常是这样做的,是的。但这可能会很麻烦。就我个人而言,在动画后从未必须手动移动视图。我相信使用平移动画时,您可以根据动画调整边距,因此如果您要向左移动30dp,则需要获取当前的marginRight值,然后再加上30dp。 - DeeV
1
由于您在主线程上启动了所有这些动画,而动画也在主线程的周期上执行,因此所有动画将同时开始。 - Sharique Abdullah

3
我已经成功地将单个Animation实例共享在多个Views之间。至少对于AlphaAnimation而言如此。我有一个ListView和一个动画,应该将其应用于所有列表项视图的特定子项。在我的情况下,这些视图可以随时“加入”和“离开”共享动画,并且不应以任何方式影响其他动画视图或干扰已经运行的动画。 为了实现这一点,我不得不制作一个调整后的android库的AlphaAnimation的副本。 虽然我的用例相当特殊,但是在这里分享出来,万一有人需要处理类似于ListView的相似目标。
/**
 * This class is a copy of android's stock AlphaAnimation with two adjustments:
 * - fromAlpha, toAlpha and duration are settable at any time.
 * - reset() method can be blocked. Reason: view.setAnimation() calls animation's reset() method
 * which is not intended in our use case.
 * For every new list item view we call setAnimation once for it's life time
 * and animation should not be reset because it is shared by all list item views and may be in progress. 
 */
public class MutableAlphaAnimation extends Animation {
    private float mFromAlpha;
    private float mToAlpha;
    private boolean resetBlocked;

    public MutableAlphaAnimation() {
    }

    public void start(float fromAlpha, float toAlpha, long duration) {
        mFromAlpha = fromAlpha;
        mToAlpha = toAlpha;
        setDuration(duration);
        setStartTime(START_ON_FIRST_FRAME);
    }

    public void setResetBlocked(boolean resetBlocked) {
        this.resetBlocked = resetBlocked;
    }

    @Override
    public void reset() {
        if (! resetBlocked) super.reset();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float alpha = mFromAlpha;
        t.setAlpha(alpha + ((mToAlpha - alpha) * interpolatedTime));
    }

    @Override
    public boolean willChangeTransformationMatrix() {
        return false;
    }

    @Override
    public boolean willChangeBounds() {
        return false;
    }
}

将动画设置到视图上:

            animation.setResetBlocked(true);
            view.setAnimation(animation);
            animation.setResetBlocked(false);

要开始一个动画(先前通过setAnimation设置),必须完成两个步骤:

        animation.start(0.0f, 1.0f, FADE_IN_DURATION);

此后,您必须手动调用invalidate()来影响动画的每个视图。

通常的startAnimation()会为您执行invalidate(),但是setAnimation不会。(请阅读android源代码中View.setAnimation()方法的注释)。


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