您的位置:首页 > 移动开发 > Android开发

Android属性动画简单总结

2017-09-27 16:58 357 查看
内容总结自郭神的三篇属性动画博客,附上链接:

Android属性动画完全解析(上),初识属性动画的基本用法

Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法

Android属性动画完全解析(下),Interpolator和ViewPropertyAnimator的用法

为什么要引入属性动画?

Android系统目前有3种动画:逐帧动画(frame-by-frame animation)和补间动画(tweened animation)以及属性动画(property animation)。逐帧动画类似于动画片,就是将完整的动画过程分成一张张单独的图片,然后连起来播放;补间动画就是对View进行一系列的操作,包括淡入淡出、平移、旋转、缩放四种。逐帧动画和补间动画技术旧了,用的不多,属性动画弥补了这两者的缺点,其优点如下:

可以对非View对象进行操作,比如有个自定义的View里面有个Point对象用于管理坐标,如果我们想操作View,就必须对Point进行操作,但是非View对象逐帧和补间做不到,属性动画可以

可以对对象进行动态操作,比如说我们要在程序中动态改变背景的颜色,由于补间和逐帧的动画机制是以硬编码的方式实现的,无法做到动态改变,属性动画可以

可以真正意义上改变View的属性,逐帧和补间虽然实现了View显示效果上的改变,但是并没有真正改变其属性,比如说我们将一个按钮拖动到别的位置,它实际上的点击位置没变,我们只有点击原位置才能激发点击事件。

属性动画实际上是对值进行操作,将值的改变赋给指定对象的指定属性上,可以是任意对象的任意属性,从而实现真正意义上的改变属性。

ValueAnimator

属性动画是对值的操作,而ValueAnimator就是负责从初始值到结束值之间的过渡动画,我们只需要给定初始值和结束值,以及动画持续时间,ValueAnimator会自动帮我们实现动画效果。

ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.setDuration(300);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentValue = (float)animation.getAnimatedValue();
Log.d("TAG", "cuurent value is " + currentValue);
}
});
anim.start();


ofFloat方法第一个参数是初始值,第二个是结束值,代码中还设置了动画监听器,动画更新时会自动回调更新方法,getAnimatedValue()用于将每次更新后的值返回。

除此之外,我们还可以调用setStartDelay()方法来设置动画延迟播放的时间,调用setRepeatCount()和setRepeatMode()方法来设置动画循环播放的次数以及循环播放的模式,循环模式包括RESTART和REVERSE两种,分别表示重新播放和倒序播放的意思。

ObjectAnimator

ObjectAnimator继承自ValueAnimator,所以父类的方法在ObjectAnimator里也可以用,此外ValueAnimator只是值的一种变化,而ObjectAnimator则真正可以对对象的属性进行修改,看个例子:

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
animator.setDuration(5000);
animator.start();


这里的ofFloat方法就更加具体了,除了值的变化,还增加了对象textview和属性”alpha”,即在5s内textview的透明度从完全不透明变化到透明再变到不透明。

ObjectAnimator中的ofXXX方法需要指定对象和属性,但是属性可以是任意的吗?答案是:任意的。因为ObjectAnimator当初的设计就不是仅仅针对View,而是对任意的对象的属性。

那对于比如说textView中我们传入的String类型的属性名,是否在TextView中有同样属性名的变量呢?答案是:没有。父类View中也没有,实际上ObjectAnimator是通过传入的属性名在对象中找与其对应的set和get方法,比如说:

public void setAlpha(float value);
public float getAlpha();


通过这两个方法来修改对象的属性,并且这两个方法是由View提供的,也就是说任何继承View的类都能使用。

AnimatorSet

实现组合动画功能主要需要借助AnimatorSet这个类,这个类提供了一个play()方法,如果我们向这个方法中传入一个Animator对象(ValueAnimator或ObjectAnimator)将会返回一个AnimatorSet.Builder的实例,AnimatorSet.Builder中包括以下四个方法:

after(Animator anim) 将现有动画插入到传入的动画之后执行

after(long delay) 将现有动画延迟指定毫秒后执行

before(Animator anim) 将现有动画插入到传入的动画之前执行

with(Animator anim) 将现有动画和传入的动画同时执行

用法如下:

ObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -500f, 0f);
ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
AnimatorSet animSet = new AnimatorSet();
animSet.play(rotate).with(fadeInOut).after(moveIn);
animSet.setDuration(5000);
animSet.start();


Animator监听器

Animator类提供了一个addListener()方法,该方法传入一个AnimatorListener,我们只需要实现这个AnimatorListener就可以实现监听功能。

无论是ValueAnimator、ObjectAnimator还是AnimatorSet都继承了Animator,所以都可以添加监听器。

添加监听器的代码如下:

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

@Override
public void onAnimationRepeat(Animator animation) {
}

@Override
public void onAnimationEnd(Animator animation) {
}

@Override
public void onAnimationCancel(Animator animation) {
}
});


如果不需要实现监听器的全部功能,可以传入一个AnimatorListenerAdapter对象,由于其已经实现了监听器的功能,我们只需要重写需要的方法即可。

anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
}
});


使用XMl编写动画

使用XMl去编写动画可能会比代码
dc88
编写要慢,但是重用起来方便,适合编写重用度高的动画。

如果想要使用XML来编写动画,首先要在res目录下面新建一个animator文件夹,所有属性动画的XML文件都应该存放在这个文件夹当中。然后在XML文件中我们一共可以使用如下三种标签:

<animator> 对应代码中的ValueAnimator

<objectAnimator> 对应代码中的ObjectAnimator

<set> 对应代码中的AnimatorSet

下面代码实现将一个视图先从屏幕外移动进屏幕,然后开始旋转360度,旋转的同时进行淡入淡出操作:

<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="sequentially" >

<objectAnimator
android:duration="2000"
android:propertyName="translationX"
android:valueFrom="-500"
android:valueTo="0"
android:valueType="floatType" >
</objectAnimator>

<set android:ordering="together" >
<objectAnimator
android:duration="3000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360"
android:valueType="floatType" >
</objectAnimator>

<set android:ordering="sequentially" >
<objectAnimator
android:duration="1500"
android:propertyName="alpha"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType" >
</objectAnimator>
<objectAnimator
android:duration="1500"
android:propertyName="alpha"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" >
</objectAnimator>
</set>
</set>

</set>


最后在代码中调用该动画如下:

Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);
animator.setTarget(view);
animator.start();


Interpolator

实际上从Android 1.0版本开始就一直存在Interpolator接口了,而之前的补间动画当然也是支持这个功能的。只不过在属性动画中新增了一个TimeInterpolator接口,TimeInterpolator中文翻译为时间插值器,作用是根据时间流逝的百分比来计算当前属性值改变的百分比,这个接口是用于兼容之前的Interpolator的。下面是TimeInterpolator常用的实现类:

BounceInterpolator:弹跳插值器,动画会有落地弹跳的效果

LinearInterpolator:线性插值器,匀速动画

DecelerateInterpolator:减速插值器,动画越来越慢

AccelerateDeceleterateInterpolator:加速减速插值器,动画两头慢中间快(系统默认的是该插值器)

OvershootInterpolator:过度插值器,动画最后会超过结束值播放一段时间再返回,就像跑步太快冲过头了

AnticipateInterpolator:助跑插值器,动画会向后退一段距离助跑,然后再开始

下面看下TimeInterpolator的源码:

public interface TimeInterpolator {
float getInterpolation(float input);
}


getInterpolation()方法中接收一个input参数,这个参数的值会随着动画的运行而不断变化,从0匀速变化到1。

显而易见,线性插值器恰好是匀速变化的,所以应该直接返回这个input,我们看下源码:

public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {

public LinearInterpolator() {
}

public LinearInterpolator(Context context, AttributeSet attrs) {
}

public float getInterpolation(float input) {
return input;
}

public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createLinearInterpolator();
}
}


可以看出直接返回了input,对于加速减速插值器,返回的是经过计算包装的input。如果我们想要获得自己的插值器,实现更复杂的功能,可以照着源码编写,只是返回的input需要运算包装。那么就有问题了:这个input返回后给哪个方法调用了呢?我们现在只是做到了随着时间的流逝,可以获得对应时间下的属性值改变的百分比,但是如何通过百分比来改变属性的值呢?这就引入了TypeEvaluator。

TypeEvaluator

TypeEvaluator的中文翻译为类型估值算法,简称估值器,它的作用是根据当前属性改变的百分比来计算改变后的属性值,系统预置的有:

IntEvaluator:针对整型属性

FloatEvaluator:针对浮点型属性

ArgbEvaluator:针对Color属性

我们来看下FloatEvaluator的源码:

public class FloatEvaluator implements TypeEvaluator {
public Object evaluate(float fraction, Object startValue, Object endValue) {
float startFloat = ((Number) startValue).floatValue();
return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
}
}


fraction是个估值小数,其实fraction就是上面input的返回值,传到估值器中根据属性变化的百分比来计算当前属性的值,然后返回每一时刻的属性值,我们可以在下面的代码中使用animator.getAnimatedValue()方法获取每一时刻的属性值。

如果我们想要实现自己的动画过渡效果,告诉系统如何让指定对象的指定属性按照我们的需求改变,就需要自定义估值器,也就是创建一个类实现TypeEvaluator,可以看下面的例子:

public class ColorEvaluator implements TypeEvaluator {

@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
String startColor = (String) startValue;
String endColor = (String) endValue;
......
}
}


ViewPropertyAnimator

我们都知道,属性动画的机制已经不是再针对于View而进行设计的了,而是一种不断地对值进行操作的机制,它可以将值赋值到指定对象的指定属性上。但是,在绝大多数情况下,主要都还是对View进行动画操作的。Android开发团队也是意识到了这一点,没有为View的动画操作提供一种更加便捷的用法确实是有点太不人性化了,于是在Android 3.1系统当中补充了ViewPropertyAnimator这个机制。

我们先来回顾一下之前的用法吧,比如我们想要让一个TextView从常规状态变成透明状态,就可以这样写:

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 0f);
animator.start();


看上去不复杂,将需要的参数传入即可,但是却不太符合我们平常面向对象的思维。而用ViewPropertyAnimator实现如下:

textview.animate().alpha(0f);


看上去简便很多,animator方法返回一个ViewPropertyAnimator对象,我们可以调用这个对象的方法去修改对象的属性,例如:

textview.animate().x(500).y(500).setDuration(5000).setInterpolator(new BounceInterpolator());


ViewPropertyAnimator的对象采用连缀的方式,将多个操作连缀在一起,先在x方向移动到500这个位置,再在y方向上移动,这样启动的时候就能同时执行。

需要注意的是:

整个ViewPropertyAnimator的功能都是建立在View类新增的animate()方法之上的,这个方法会创建并返回一个ViewPropertyAnimator的实例,后面连缀的方法每次执行完一个后,还是返回该实例,这样可以通过一行代码实现对View的操作。

在使用ViewPropertyAnimator时,我们自始至终没有调用过start()方法,这是因为新的接口中使用了隐式启动动画的功能,只要我们将动画定义完成之后,动画就会自动启动。并且这个机制对于组合动画也同样有效,只要我们不断地连缀新的方法,那么动画就不会立刻执行,等到所有在ViewPropertyAnimator上设置的方法都执行完毕后,动画就会自动启动。当然如果不想使用这一默认机制的话,我们也可以显式地调用start()方法来启动动画。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 动画