相关文章
Android 动画之视图动画
Android 动画之插值器
Android 动画之属性动画ValueAnimator
Android 动画之属性动画ObjectAnimator
Android 动画之集合动画AnimatorSet
Android 动画之布局动画
视图动画(View Animation)和属性动画(Property Animation)他们分别继承于Animation和Animator两种不同的抽象类。所以从根本上也将他们做了不同类型的区分。View Animation有个AnimationSet,Property Animation有个AnimatorSet,所以在代码上区分View Animation和Property Animation时,我们只要看他们的结尾处是animation还是animator就可以判断它是视图动画还是属性动画。本文主要介绍AnimatorSet的使用,set就是集合的意思,AnimatorSet就是将多个属性动画集合在一起使用。下面来看代码具体的实现吧。
XML中的用法
文件保存路径
res/animator/filename.xml
语法:
<set
android:ordering=["together" | "sequentially"]>
<objectAnimator
android:propertyName="string"
android:duration="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]/>
<animator
android:duration="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]/>
<set>
...
</set>
</set>
例子:
res/animator/setanimator.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="sequentially">
<objectAnimator
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:propertyName="alpha"
android:duration="3000"
android:valueType="floatType"
android:valueFrom="0"
android:valueTo="1"/>
<objectAnimator
android:interpolator="@android:anim/anticipate_overshoot_interpolator"
android:propertyName="scaleX"
android:duration="3000"
android:valueType="floatType"
android:valueFrom="0.5"
android:valueTo="1.5"
></objectAnimator>
</set>
代码中的应用
AnimatorSet animatorSet = (AnimatorSet) AnimatorInflater.loadAnimator(SetActivity.this, R.animator.setanimator);
animatorSet.setTarget(textView);
animatorSet.start();
从代码中可以看出AnimationSet和ObjectAnimator的使用差不多,只是AnimatorSet可以将多个属性动画集合起来使用。
代码中动态创建
AnimatorSet提供了4中方法用于集合动画的创建。
playSequentially(Animator... items)
playSequentially(List<Animator> items)
playTogether(Animator... items)
playTogether(Collection<Animator> items)
这里它主要有两种操作类型,Sequentially和Together,通过它们的英文意思,我们可以知道就是系列和一起的意思,放在这个方法里面来理解的话就是依次播放还是同时播放。目前,这还只是我们的猜测,我们在代码中实际操作验证一下。
ObjectAnimator animatorA = ObjectAnimator.ofFloat(textView, "TranslationX", -300, 300, 0);
ObjectAnimator animatorB = ObjectAnimator.ofFloat(textView, "scaleY", 0.5f, 1.5f, 1f);
ObjectAnimator animatorC = ObjectAnimator.ofFloat(textView, "rotation", 0, 270, 90, 180, 0);
AnimatorSet animatorSet2 = new AnimatorSet();
animatorSet2.playTogether(animatorA, animatorB, animatorC);
animatorSet2.setDuration(3*1000);
animatorSet2.start();
上面实现的效果就是animatorA、animatorB、animatorC同时开始执行。如果是playSequentially的话就是animatorA、animatorB、animatorC依次执行,就不上代码了。接下来我们看下AnimatorSet提供的Build类。
public class Builder {
private Node mCurrentNode;
Builder(Animator anim) {
mCurrentNode = mNodeMap.get(anim);
if (mCurrentNode == null) {
mCurrentNode = new Node(anim);
mNodeMap.put(anim, mCurrentNode);
mNodes.add(mCurrentNode);
}
}
public Builder with(Animator anim) {
Node node = mNodeMap.get(anim);
if (node == null) {
node = new Node(anim);
mNodeMap.put(anim, node);
mNodes.add(node);
}
Dependency dependency = new Dependency(mCurrentNode, Dependency.WITH);
node.addDependency(dependency);
return this;
}
public Builder before(Animator anim) {
Node node = mNodeMap.get(anim);
if (node == null) {
node = new Node(anim);
mNodeMap.put(anim, node);
mNodes.add(node);
}
Dependency dependency = new Dependency(mCurrentNode, Dependency.AFTER);
node.addDependency(dependency);
return this;
}
public Builder after(Animator anim) {
Node node = mNodeMap.get(anim);
if (node == null) {
node = new Node(anim);
mNodeMap.put(anim, node);
mNodes.add(node);
}
Dependency dependency = new Dependency(node, Dependency.AFTER);
mCurrentNode.addDependency(dependency);
return this;
}
public Builder after(long delay) {
// setup dummy ValueAnimator just to run the clock
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(delay);
after(anim);
return this;
}
}
通过查看Build的代码,可以知道它的构造函数不是public的,所以我们只能通过AnimatorSet的play方法来获得Buidler对象。Builder提供了before、after、with等方法,我们来看下代码中的实际应用。
ObjectAnimator animatorA = ObjectAnimator.ofFloat(textView, "TranslationX", -300, 300, 0);
ObjectAnimator animatorB = ObjectAnimator.ofFloat(textView, "scaleY", 0.5f, 1.5f, 1f);
ObjectAnimator animatorC = ObjectAnimator.ofFloat(textView, "rotation", 0, 270, 90, 180, 0);
AnimatorSet animatorSet3 = new AnimatorSet();
animatorSet3.play(animatorA).after(animatorC).before(animatorB);
animatorSet3.setDuration(3*1000);
animatorSet3.start();
实现的效果就是先播放animatorC的动画,再播放animatorA的动画,最后在播放animatorB的动画。
其实,我们通过查看playSequentially和playTogether的源码知道,它们的实现也是通过调用Build类实现的,下面给出playTogether的源码。
public void playTogether(Animator... items) {
if (items != null) {
mNeedsSort = true;
Builder builder = play(items[0]);
for (int i = 1; i < items.length; ++i) {
builder.with(items[i]);
}
}
}
通过上面的代码知道playTogether的实现就是通过调用了builder.with()实现了动画的同时播放。AnimatorSet的介绍就差不多讲完了,感兴趣的同学一定要多动手去敲敲代码,加深理解。
源代码
参考文章
Animation Resources
自定义控件三部曲之动画篇(九)——联合动画的代码实现
自定义控件三部曲之动画篇(十)——联合动画的XML实现与使用示例