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 | 动画集合类,可以加入过个动画,设置动画的执行顺序。让集合中的动画按照执行顺序执行。 |
类 | 描述 |
---|---|
IntEvaluator | Int属性默认使用 |
FloatEvaluator | Float属性默认使用 |
ArgbEvaluator | Color属性默认使用 |
TypeEvaluator | 接口类,用于实现自定义的evaluator。例如,当你创建属性动画,属性值不是int,float和color类型,那么这个时候,你就必须要通过自定义Evaluators来实现了属性动画了。 |
类/接口 | 描述 |
---|---|
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相关文章推荐
- Android-XML转成View过程简述
- android热补丁初探之二 热补丁分析对比
- Android-Frame Animation介绍
- android onSaveInstanceState方法
- RecyclerView 的研究和使用
- android中px,dp,sp
- Android开发中遇到的字符串、十六进制和Byte转换,及十六进制校验等函数集
- android错误之MediaPlayer用法的Media Player called in state *,androidmediaplayer
- Android模拟器上网
- android PhoneGap跨平台笔记1--helloword
- Android 中常见的小知识总结
- Android之自定义属性
- Android Support Design Library - CoordinatorLayout
- android中的文件(图片)上传
- android开发50个小技巧
- android开发之应用Crash自动抓取Log_自动保存崩溃日志到本地
- android CoordinatorLayout使用
- 升级Android ADT 和SDK
- Android当中的多线程及AsyncTask
- Android应用如何开机自启动、自启动失败原因