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

Android-Preproty animation解析

2016-03-11 19:46 232 查看

android-Property Animation介绍

属性动画(property animation)系统,是一个健壮的框架,可以实现任何将任何属性设置为动画。不管对象是否被绘制到屏幕上,你都可以声明一个动画去改变它的属性值。属性动画是指在定长时间内改变指定属性的一种动画。

你可以从下面这些特性入手去定义一个属性动画(property animation):

Duration(持续时间):你可以指定动画的持续时间,默认值为300ms

Time interpolation(时间插值器):你可以指定属性值和动画已执行时间之间的换算方法

Repeat count and behavior(动画重复次数和重复的方式):你可以指定动画的重复次数。同时,你也可以指定动画重复的模式,例如是从头到尾从头到尾的效果,还是重头到尾再从尾到头。

Animator sets(动画集合):你可以将一系列动画都放入一个动画集合中。之后,通过设置动画集合,以同时或有序或指定掩饰的方式播放那一系列的动画。

Frame refresh delay(帧刷新时间):你可以指定播放动画时,刷新屏幕的时间间隔。默认刷新时间是10ms,但是具体有系统决定。

属性动画工作流程

先来看一个简单的例子,图1描述了一个拥有改变x属性的动画的对象,图中x轴坐标系与屏幕表面平行。动画持续40ms,每10ms,屏幕刷新一次,同时对象向x轴坐标方向前进10像素点。在40ms结束之后,动画停止,对象停留在x轴坐标为40的位置。这个例子,其实采用的是一个linear interpolation,抽象类指定属性匀速变化。



图1.线性动画实例

介绍了线性动画,接下来让我们来看看非线性动画吧。图2为同样也是描述了一个拥有沿x轴运动动画的对象。不同之处在于,动画不是匀速运动,而是一开始先加速,到快结束时减速的动画。这个动画也是在40ms内运动了40像素点,但不是线性运动。从图中可以看出,动画从起始点到中点进行加速;之后,从中点到结束点进行减速。



图2.非线性动画实例

通过图3,详细介绍属性动画是怎么实现的。



图3.实现原理图

详细介绍:

其中的ValueAnimator是动画的执行类,跟踪了当前动画的执行时间和当前时间下的属性值;ValueAnimator封装了动画的TimeInterpolator和TypeEvaluator。TypeEvaluator用来计算设置动画属性的值。例如图2中,动画采用TimeInterpolator是AccelerateDecelerateInterpolator,然后TypeEvaluator是IntEvaluator。

为了执行一个动画,需要创建一个ValueAnimator对象并指定目标对象的开始值,结束值和持续时间。在调用star()方法后,动画开始。在整个动画过程中,ValueAnimator对象计算动画执行进度百分数,动画进度从0~1。当动画刚刚开始的时候,进度为0,%0;当动画结束时,进度为1,%100。例如图1,当执行了10ms之后,进度为0.25,因为从时间为40ms。

当ValueAnimator算出了动画执行进度之后,ValueAnimator调用当前设置的TimeInterpolator接口对象,去计算interpolator插值(0~1之间)。TimeInterpolator对象通过一定函数将动画执行进度转化为插值分数。例如图2,动画一开始速度比较慢;当动画执行10ms时,动画执行进度为0.25,插值分数为0.15。在比如图1,动画为线性动画,当动画执行10ms时,动画执行进度与插值分数始终相等。

当插值分数计算完成后,ValueAnimator会根据插值分数调用合适的 TypeEvaluator去计算运动中的属性值。例如图2,在动画执行10ms后,动画进度为0.15,动画属性值为:0.15*(40-0),6。

官方例子:

http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/animation/index.html

Property Animation和View Animation不同之处

View Animation只作用于View类及其子类,并且View Animation只作用于视图的位置,大小,旋转,透明度这4方面。View Animation只能改变View被绘制的位置和形式,对View本身属性不做任何改变。

在上面那些方面,Property Animation对View Animation补充。Property Animation可以对任何对执行动画,同时动画属性值真正的发生了变化。

API Overview

**表1**Animator动画执行类

描述
ValueAnimator属性动画执行类,他包含核心功能:计算动画属性值,控制每个动画执行时间,保存动画信息(是否重复执行等),设置动画监听。ValueAimator可以说要一个半自动动画执行类。对于计算动画完成进度,设置动画属性值,更新屏幕帧这类的处理,ValueAnimator是自动完成的。但是对于计算属性值这类的处理,需要我们自己完成。之后,我们会展开实例。
ObjectAnimator属性动画执行类,ObjectAnimator是ValueAnimator的子类。此类,相当于在ValueAnimator的基础上,进行了封装。你可以快速创建此类动画。
AnimatorSet动画集合类,可以加入过个动画,设置动画的执行顺序。让集合中的动画按照执行顺序执行。
表2 Evaluators(估值)

描述
IntEvaluatorInt属性默认使用
FloatEvaluatorFloat属性默认使用
ArgbEvaluatorColor属性默认使用
TypeEvaluator接口类,用于实现自定义的evaluator。例如,当你创建属性动画,属性值不是int,float和color类型,那么这个时候,你就必须要通过自定义Evaluators来实现了属性动画了。
**表3**Interpolators(插值器)

类/接口描述
AccelerateDecelerateInterolator先加速后减速
AccelerateInterpolator加速
DecelerateInterpolator减速
AnticipateInterpolator先向相反方向改变一段再加速播放
AnticipateOvershootInterpolator先向相反方向改变,再加速播放,会超出目标值然后缓慢移动至目标值,类似于弹簧回弹
BounceInterpolator快到目标值时值会跳跃
CycleIinterpolator动画循环一定次数,值的改变为一正弦函数:Math.sin(2 * mCycles * Math.PI * input)
LinearInterpolator线性均匀改变
OvershottInterpolator最后超出目标值然后缓慢改变到目标值
TimeInterpolator一个允许自定义Interpolator的接口,以上都实现了该接口
介绍了那么多的概念,我们还是得回归到实践中去。毕竟理论源于实践嘛~

接下来,我们从最简单的ObjectAnimator开始,毕竟ObjectAnimator是系统已经给我们封装好了的类。

ObjectAnimator动画例子

布局文件

后面所有例子,都采用此布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="0dp"
tools:context="com.example.abe.propertyanimation.MainActivity">

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Hello World!" />

</RelativeLayout>


Activity代码

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

button = (Button) findViewById(R.id.button);
button.setOnClickListener(this);
}
public void onClick(View v) {

//        实现单个属性值改变动画
//        ObjectAnimator
//                .ofFloat(button, "x", 100F)
//                .setDuration(500)
//                .start();

//        实现多个属性值改变动画
PropertyValuesHolder pvhAlpha = PropertyValuesHolder.ofFloat("alpha", 1f, 0f);
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x",1f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y",1f);
ObjectAnimator.
ofPropertyValuesHolder(button, pvhAlpha, pvhX, pvhY)
.setDuration(1000)
.start();
}
}


在Onclick方法在,实现了多属性动画代码和单属性动画代码。下面是他们的实现效果图





ObjectAnimator总结

提供了ofInt、ofFloat、ofObject,这几个方法都是设置动画作用的元素、作用的属性、动画开始、结束、以及中间的任意个属性值。

当对于属性值,只设置一个的时候,会认为当然对象该属性的值为开始(getPropName反射获取),然后设置的值为终点。如果设置两个,则一个为开始、一个为结束

动画更新的过程中,会不断调用setPropName更新元素的属性,所有使用ObjectAnimator更新某个属性,必须得有getter(设置一个属性值的时候)和setter方法~

如果你操作对象的该属性方法里面,比如上例的setRotationX如果内部没有调用view的重绘,则你需要自己按照下面方式手动调用。

anim.addUpdateListener(new AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
view.postInvalidate();
view.invalidate();
}
});


ValueAnimator动画例子

ValueAnimator动画例子中使用的布局,还是采用ObjectAnimator例子中的布局。

java代码

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private Button button;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

button = (Button) findViewById(R.id.button);
button.setOnClickListener(this);
}

@Override
public void onClick(View v) {

ValueAnimator animator = new ValueAnimator();
animator.setObjectValues(new PointF(0, 0));
animator.setTarget(button);

//        模拟线性插值器
animator.setInterpolator(new TimeInterpolator() {
@Override
public float getInterpolation(float input) {
return input;
}
});

//        自定义抛物线
animator.setEvaluator(new TypeEvaluator<PointF>() {
// fraction = t / duration
@Override
public PointF evaluate(float fraction, PointF startValue,
PointF endValue) {
PointF point = new PointF();
point.x = 200 * fraction * 3;
point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);
return point;
}
});

//        监听动画更新,同时设给对应属性值
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
PointF point = (PointF) animation.getAnimatedValue();
button.setX(point.x);
button.setY(point.y);

}
});

animator.setDuration(1000).start();
}
}




ValueAnimator总结

通过上面的ValueAnimator动画例子,我们实现了自定义ValueAnimator动画的一个完成过程。其实这个动画工作流程,我们在一开始的
属性动画工作流程
中已经讲过了,下面结合代码深入说明。

实现ValueAnimator动画,总计为4步:

创建ValueAnimator对象。

设置Interpolator(插值器),插值器,主要用于计算插值。ValueAnimator调用TimeInterpolator类中的
public float getInterpolation(float input)
方法,计算interpolator插值(0~1之间)。关于插值的计算方法,我们此方法中自定义实现。

/*
* @param 参数input为ValueAnimator提供的动画完成进度值
* @return 返回值为动画插值
public float getInterpolation(float input){

}


如果我们不自定义Interpolator(插值器),也可以使用系统提供的插值器,插值器在表3中已经列出来了。常用插值器,设置方法

animator.setInterpolator(new LinearInterpolator());


设置TypeEvaluator(类型估值),主要用于计算属性值,ValueAnimator会根据插值分数调用evaluator去计算运动中的属性值。在例子中,我们是自定义的方式,来计算运动中的属性值。实现TypeEvaluator自定义,我们需要实现下面方法。

/*
* @param 参数fraction为刚才Interpolator(插值器)计算出来的插值
* @param 参数startValue为动画开始值(本方法不作使用)
* @param 参数endValue为动画结束值(本方法不作使用)
* @return 计算得到的动画属性值
public PointF evaluate(float fraction, PointF startValue,
PointF endValue) {
PointF point = new PointF();
point.x = 200 * fraction * 3;
point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);
return point;
}


此方法作用,就是通过计算,将之前计算出来的插值变成动画属性值。

如果满足条件,我们也可以使用系统提供的TypeEvaluator。在表3中已经列出了系统提供的类型估值。常用类型估值,设置方法如下:

animator.setEvaluator(new IntEvaluator());


设置属性值。将TypeEvaluator中计算出来的动画属性值赋值给对象。在ObjectAnimator中,系统为我们做好了这一步,但是在ValueAnimator中我们需要自己来完成。下面是完成方法:

animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//我们也可以将属性值,设置给多个对象,或者一个对象的多个值
//设置完全自定义的
PointF point = (PointF) animation.getAnimatedValue();
button.setX(point.x);
button.setY(point.y);
}
});


AnimatorSet动画例子

布局,还是原来的布局~

java代码

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private Button button;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

button = (Button) findViewById(R.id.button);
button.setOnClickListener(this);
}

@Override
public void onClick(View v) {
//        ObjectAnimator anim1 = ObjectAnimator.ofFloat(button, "x", 0f);
//        ObjectAnimator anim2 = ObjectAnimator.ofFloat(button, "y", 0f);
//        AnimatorSet animSet = new AnimatorSet();
//        animSet.setDuration(2000);
//        animSet.setInterpolator(new LinearInterpolator());
//        //两个动画同时执行
//        animSet.playTogether(anim1, anim2);
//        animSet.start();

ObjectAnimator anim1 = ObjectAnimator.ofFloat(button, "x", 0f);
ObjectAnimator anim2 = ObjectAnimator.ofFloat(button, "y", 0f);
ObjectAnimator anim3 = ObjectAnimator.ofFloat(button, "alpha",
1f, 0f);
AnimatorSet animSet = new AnimatorSet();
animSet.setDuration(2000);
animSet.setInterpolator(new LinearInterpolator());
//三个动画执行顺序:anim1 -> anim2 -> anim3
animSet.play(anim1).before(anim2);
animSet.play(anim3).after(anim2);
animSet.start();
}
}


在此例子中,我们实现了两个动画集合。其中,注释掉部分,两个动画同时执行;而没注释部分,则是按照anim1 -> anim2 -> anim3的顺序执行的。下面是效果图:





AnimatorSet总结

AnimatorSet设置动画执行顺序,常用方法介绍:

表4

方法描述
Builder before(Animator anim)动画在anim之后执行
Builder with(Animator anim)动画和anim同时执行
Builder after(Animator anim)动画在anim之前执行
void playTogether(Animator… items)items中的所有动画,同时执行

参考

http://developer.android.com/intl/zh-cn/guide/topics/graphics/prop-animation.html#views
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: