第二次看属性动画,结合两本书的介绍和郭神的博客来总结一下。
Android3.0之后的动画系统是 帧动画,属性动画,补间动画三足鼎立的局面。
那么他们各自有各自的优缺点,但是属性动画是相对先进的技术,至少它能解决view移动事件不移动的情况,它还带来了更多丰富的效果和更丰富的接口来开发提升的效率。
那其实属性动画能带来的不只有这些,具体的好处可以在文末的连接参考郭神的博客,大神写的更加详细。(同时本篇里的部分代码借鉴于郭神的代码)
1.ValueAnimator
在说属性动画效果之前必须先讨论这个东西。
ValueAnimator的作用并不是产生动画效果,而是以特定算法来计算属性值,通过得到属性值,Animator就可以对Object进行一系列的动画,除此之外,ValueAnimator对于动画管理,监听器等地方也有所作用。
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,100);
valueAnimator.setTarget(textView);
valueAnimator.setDuration(1000).start();
valueAnimator.addUpdateListener(new
ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Float f = (Float) animation.getAnimatedValue();
//Log打印f
}
});
我们需要搞到一个ValueAnimator对象,那么其实是通过静态工厂类返回对象,比如说我们调用的ofFloat方法,这里传入一个可变参数,比如说我们给的(0,100),
//Android源码
public static ValueAnimator ofFloat(float... values) {
ValueAnimator anim = new ValueAnimator();
anim.setFloatValues(values);
return anim;
}
当我们start这个动画之后,并给其添加一个动画的更新监听器,在终端打印下float的值,你可以看到在1000ms的时间内,从0-100的特定规律变化
如果你想实现其他形式的变化可以如下:
//0->5->3->10的跳跃性变化
ValueAnimator anim = ValueAnimator.ofFloat(0f, 5f, 3f, 10f);
//整数型变化
ValueAnimator anim = ValueAnimator.ofInt(0, 100);
当然作为动画数值生成类也是有setRepeat , setRepeatMode之类的方法,主要是对数据进行一些花样的处理(同时也是满足不同的动画效果,这些也是在补间动画上有的)
2.ObjectAnimator
到这里才进入了我们真正的效果阶段,我们真实能看到效果的,展现到屏幕上的是ObjectAnimator,那前面说过,其实ObjectAnimator是基于ValueAnimator的数值变化来完成的,也可以说是ValueAnimator在后面默默地工作,ObjectAnimator才能展示出效果。
同样的ObjectAnimator的用法也是跟ValueAnimator差不多的,通过静态工厂返回对象,通过ofFloat来设置参数,最后设置区间启动动画。
比如下面的textview的透明度从不透明到全透明到不透明。
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
animator.setDuration(5000);
animator.start();
ofFloat源码如下
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
anim.setFloatValues(values);
return anim;
}
参数1:Object目标,也就是我们要实现动画的东西,不仅限于view
参数2:propertyName,属性名称,也就是我们要实现什么动画
参数3:可变参数,主要是实现的动画的动画参数
这样的话一个简单的属性动画就实现了。
同样其他动画效果
//旋转360°
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
animator.setDuration(5000);
animator.start();
//当前位置平移-500(左移),然后移动回来
float curTranslationX = textview.getTranslationX();
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "translationX", curTranslationX, -500f, curTranslationX);
animator.setDuration(5000);
animator.start()
那么更多的效果也是可以用类似的方法来实现的。
具体的有以下几种:
translationX & translationY :X与Y轴的平移效果
rotationX & rotationY & rotation:围绕view本身的旋转效果
PrivotX & PrivotY:围绕着View中心点(默认)旋转缩放的效果
scaleX & scaleY:中心点缩放的动画
alpha:透明度动画
但是我们为什么能用这些动画呢,还记得在之前说过属性动画不仅是用于view的,而是可以用于任何地方,那么这就说明属性动画设计的时候没有view限制,我们可以给第二个参数传任何的值进去,但是前提是对象有get/set方法,什么意思呢,拿textview举例,我们在textview的源码中可以找到setAlpha()方法如下:
public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
ensureTransformationInfo();
if (mTransformationInfo.mAlpha != alpha) {
// Report visibility changes, which can affect children, to accessibility
if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) {
notifySubtreeAccessibilityStateChangedIfNeeded();
}
mTransformationInfo.mAlpha = alpha;
if (onSetAlpha((int) (alpha * 255))) {
mPrivateFlags |= PFLAG_ALPHA_SET;
// subclass is handling alpha - don't optimize rendering cache invalidation
invalidateParentCaches();
invalidate(true);
} else {
mPrivateFlags &= ~PFLAG_ALPHA_SET;
invalidateViewProperty(true, false);
mRenderNode.setAlpha(getFinalAlpha());
}
}
}
具体代码在这里不解释,正是因为有了这个方法,我们的alpha动画才可以生效,所以你大概可以明白,当我们的object木有PropertyName的get/set方法的时候,我们是没法进行动画实现的。
那么其实现在你就明白了属性动画的强大了,它给予你非常大的自定义空间,你可以给任何对象添加你想要的实现。
然后如果你想实现一个动画监听器的话
objectAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
//动画开始
}
@Override
public void onAnimationEnd(Animator animation) {
//动画结束
}
@Override
public void onAnimationCancel(Animator animation) {
//动画取消
}
@Override
public void onAnimationRepeat(Animator animation) {
//动画重复
}
});
当然系统还提供了适配器来解决只选择必要的方法重写的功能。
objectAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationRepeat(Animator animation) {
super.onAnimationRepeat(animation);
}
});
3.组合动画
虽然我们已经可以实现简单的动画,但是产品总是会有很多神奇的想法,今天实现这么个动画,明天实现这个动画,各种奇怪的需求,你不得不寻找解决办法,但是在属性动画中,官方也给了相应API来实现,可以说是很不错的。
实现组合动画功能主要需要借助AnimatorSet这个类,这个类提供了一个play()方法,如果我们向这个方法中传入一个Animator对象(ValueAnimator或ObjectAnimator)将会返回一个AnimatorSet.Builder的实例
那么AnimatorSet.Builder的源码如下:
public class Builder {
private Node mCurrentNode;
Builder(Animator anim) {
mDependencyDirty = true;
mCurrentNode = getNodeForAnimation(anim);
}
public Builder with(Animator anim) {
Node node = getNodeForAnimation(anim);
mCurrentNode.addSibling(node);
return this;
}
public Builder before(Animator anim) {
mReversible = false;
Node node = getNodeForAnimation(anim);
mCurrentNode.addChild(node);
return this;
}
public Builder after(Animator anim) {
mReversible = false;
Node node = getNodeForAnimation(anim);
mCurrentNode.addParent(node);
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;
}
}
Builder是构建者,每次调用都会返回builder自身用于继续构建,这四个方法分别是:
- after(Animator anim) 将现有动画插入到传入的动画之后执行
- after(long delay) 将现有动画延迟指定毫秒后执行
- before(Animator anim) 将现有动画插入到传入的动画之前执行
- with(Animator anim) 将现有动画和传入的动画同时执行
通过这样我们就可以控制动画播放顺序,来实现想要的效果。
ObjectAnimator animator1 = ObjectAnimator.ofFloat(textView,"translationX",0.0f,200.0f,0f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(textView,"scaleX",1.0f,2.0f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(textView,"rotationX",0.0f,90.0f,0f);
AnimatorSet set = new AnimatorSet();
set.setDuration(1000);
set.play(animator1).with(animator2).after(animator3);
set.start();
4.XML实现
在以前实现动画效果的时候我们可以用xml来实现,当然属性动画也不例外,有了xml代码我们可以节省时间空间,很方便的调用,会达到一个代码的复用,使用之前首先在res中建立animator(这个是为属性动画准备的)文件夹,那么在XML文件中我们一共可以使用如下三种标签:
这里搬郭神的一段代码来,这是使用xml来完成一个动画集合的效果,当然如果写单个动画只需要写
一部分。
在java中的调用是这样的
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);
animator.setTarget(view);
animator.start();
首先加载动画文件,绑定视图,最后启动动画。
属性动画的介绍就这么多,肯定不如郭神讲的详细,下面也给了郭神的文章链接,更多的请访问。
参考:http://blog.csdn.net/guolin_blog/article/details/43536355