属性动画的简单使用和总结
2016-01-27 15:59
561 查看
推荐一本书—《android开发艺术探索》,内容很好很强大,这里也算是个读书笔记吧,在此膜拜一下作者刚哥,期待刚哥的配套视频。。。
在API版本11的时候,andriod新引进了一个新的动画:属性动画,相比之前的View动画,属性动画功能强大,它可以对任何对象的任何属性做动画,不仅仅只是view,而且在动画效果上,属性动画也不像view动画那样只局限与平移、缩放、旋转、透明度这四种,各种各样的自定义绚丽的效果都可以实现。
常用的动画类:ValueAnimator、ObjectAnimator、AnimatorSet,从类名可以看到,这分别是值动画、对象动画、动画集合。ObjectAnimator对象动画是继承于ValueAnimator动画的
一、ValueAnimator—值动画
单纯的ValueAnimator并不常用,因为只是单纯的对值进行操作而不赋予对象的属性上的话,意义并不大,用法很简单,将一个值在1秒内从0过渡到1,可以这么写:
这样动画就可以运行了,只是看不出来,因为单纯的一个值的变化在屏幕上是一片空白,不过可以通过监听器来监控动画,添加监听有两种方法,addListener和addUpdateListener,分别对应不同的监听器。
addListener对应的是AnimatorListener监听器,可以使用如下代码添加:
但是一般情况下,我们并不需要监听这么多状态,所以官方提供了另外一种方式,如下:
AnimatorListenerAdapter是一个AnimatorListener的适配器类,它已经实现了AnimatorListener的所有接口,所以使用它的时候不必将每一个方法都实现,只需要在需要的地方重写就可以了,其他的都会是默认实现。
PS:此类监听器本人习惯称之为状态监听器(有开始、结束、重复、取消等状态)
系统还提供了另外一种监听方法:addUpdateListener,对应的监听器为AnimatorUpdateListener,使用方法如下:
和上面的状态监听器不同的是,这个AnimatorUpdateListener监听器监听的是动画的实时更新,动画是由很多帧组成了,每播放一帧,onAnimationUpdate方法就会调用一次。
PS:此类监听器本人习惯称为进行时监听器,它监听的是动画的实时播放。
ValueAnimator常用的方法:
二、ObjectAnimator对象动画
和ValueAnimator值动画相比,ObjectAnimator对象动画用的就比较多,它的功能相当强大,几乎可以对任何对象的任意属性做动画,用法也很简单,如下:
上面的方法的第一个参数是目标对象,这里是一个textView,第二个参数是目标对象的目标属性,这里是translationX,后面是若干个属性值。translationX属性控制着控件的X坐标,将一个textView的translationX的属性做动画,X坐标不停的变换,那么整个控件就会产生了动画效果。
属性动画机制其实是不停的给对象(比如View)的某个属性赋值(比如translationX),每一次赋值一般都会触发视图重绘(如果没有那么不会产生动画效果,需要自己手动强制重绘),内部原理其实是:属性动画在改变对象的某个属性的时候(比如属性abc),需要对象提供方法setAbc,这样属性动画就会根据外部传进来的初始值和最终值进行多次调用setAbc方法来给相应的属性赋值,这样在一个时间段内,属性abc被多次改变,越来越接近最终值,如果有触发重绘的话,就会产生动画。
两个注意点:
1、 想要通过属性动画来使对象的某个属性abc进行改变,那么对象就要有setAbc方法,同时,外部传值的时候如果没有初始值,那么对象还需要提供getAbc方法用来获取初始值。
2、 想要有动画的效果,那么对象的属性在改变的时候需要造成UI的改变,否则看不到动画效果。
至于监听器方面,由于ObjectAnimator是继承于ValueAnimator,所以用法和ValueAnimator是一样的,不多说。
三、AnimatorSet 动画集合
真正的项目中的动画都是绚丽多彩的,仅仅靠一个动画很难实现,所以动画集合AnimatorSet也很常用,用法也很简单,如下:
也可以这样:
方法很简单,AnimatorSet动画集合有两种方式,一个就是有序播放,还一个就是同时播放
四、使用xml方式来播放动画
和之前的view动画一样,属性动画也可以写在xml中,方便复用,代码也很简单,在res目录中创建animator文件夹,创建animator.xml文件,内容如下:
其中animator是ValueAnimator,objectAnimator对应的是ObjectAnimator,Set对应的是动画集合AnimatorSet,set动画集合有一个属性是ordering,两个值,sequentially代表的是有序,together代表同时,其他的代码很简单,就不多做解释了,注意一点,当改动的属性propertyName是颜色的时候,valueType就不需要指定了,系统会自动处理。
使用xml方式的动画可以复用,但是加载会稍微慢一些,而且需要提前知道初始值和结束值并且固定,代码中的动画无法复用,但是加载速度快,初始值和结束值不需要定死,实际使用可以按照需求来选择。
五、TypeEvaluater估值器和TimeInterpolator 时间插值器
1、TypeEvaluater估值器
作用是根据当前属性改变的百分比来计算改变之后的属性值
TypeEvaluater是一个接口,里面只有一个方法,如下:
这个方法有三个参数,第一个参数是浮点类型fraction,意味着当前属性改变的百分比,后面两个参数代表这初始对象和终止对象,通过一系列算法最后返回一个同样的对象,这个返回的对象就是当前瞬间的状态,拿系统提供的IntegerEvaluator为例
这里面的对象就是一个整形,传进去的三个参数中,结束值减去初始值就是整个的变化区间,乘以当前的属性改变百分比,就是当前变化的值,再加上初始值返回,即当前瞬间的值。
初始值和结束值肯定是外部传进去的,那么第一个参数fraction(属性改变的百分比)是从哪里得到的呢,其实是从TimeInterpolator时间插值器中得到的。
2、TimeInterpolator时间插值器
作用是根据时间变化百分比来计算当前属性改变的百分比
同样,先看看接口
接口方法也很简单,只有一个方法,方法中的参数input是从系统中获得,这个参数的值随着动画的运行不断变化,并且是匀速变化,可以理解为“时间”,时间流逝是匀速的,这里面就是根据时间流逝百分比来计算属性变化的百分比,返回一个瞬时的浮点型,这个浮点型就是估值器中的fraction。
流程:动画开始–>插值器算法通过时间流逝得到属性变化百分比fraction–>估值器算法通过属性变化百分比得到当前属性值–>动画结束。
常用的系统提供的插值器有:
LinearInterpolator线性插值器(匀速变化)、AccelerateDecelerateIntepolator加速减速插值器、
AccelerateIntepolator加速插值器和DecelerateIntepolator减速插值器等,如果要自定义插值器就需要实现Interpolator或者TimeInterpolator。
常用的系统提供的估值器有:
FloatEvaluator浮点估值、IntEvaluator整形估值、ArgbEvaluator颜色估值器,如果自定义估值器的话就需要实现TypeEvaluator。
六、对任意属性做动画
前面说属性动画原理机制的时候提到过,要想有动画效果,需要两个注意点:
1、 想要通过属性动画来使对象的某个属性abc进行改变,那么对象就要有setAbc方法,同时,外部传值的时候如果没有初始值,那么对象还需要提供getAbc方法用来获取初始值。
2、 想要有动画的效果,那么对象的属性在改变的时候需要造成UI的改变,否则看不到动画效果。
那么如果想要给某个对象做动画,但是对象并没有提供相应的setAbc方法,或者相应的setAbc方法并没有达到想要的效果,比如TextView的setWidtht方法,并不是控制了View的宽度,而是最小和最大宽度,所以这种情况下,就需要自己想办法。
分析要想达到的效果是:宽度不停的变化从而产生动画。
有两种方法可以实现:
1、 对目标对象进行包装,定义set和get方法,在set方法内进行目标对象的属性变化并且更新UI
例如:
在外部调用的时候就需要如此写即可
2、 ValueAnimator类中可以添加进行时监听器addUpdateListener,监听每一帧的变化,并且每一帧都会调用,那么直接在方法内添加对对象属性的改变并且重新绘制即可,这样就会在每一帧的时候变化对象的属性,继而产生动画。如下:
这个其实就是利用了监听器,进行时监听器监听的是动画的实时播放,所以在方法内做属性的改变,每一帧调用一次,整体就形成了动画…
PS:总感觉类似于“挂载”?
在API版本11的时候,andriod新引进了一个新的动画:属性动画,相比之前的View动画,属性动画功能强大,它可以对任何对象的任何属性做动画,不仅仅只是view,而且在动画效果上,属性动画也不像view动画那样只局限与平移、缩放、旋转、透明度这四种,各种各样的自定义绚丽的效果都可以实现。
常用的动画类:ValueAnimator、ObjectAnimator、AnimatorSet,从类名可以看到,这分别是值动画、对象动画、动画集合。ObjectAnimator对象动画是继承于ValueAnimator动画的
一、ValueAnimator—值动画
单纯的ValueAnimator并不常用,因为只是单纯的对值进行操作而不赋予对象的属性上的话,意义并不大,用法很简单,将一个值在1秒内从0过渡到1,可以这么写:
ValueAnimator ani = ValueAnimator.ofFloat(0f,1f); ani.setDuration(1000); ani.start();
这样动画就可以运行了,只是看不出来,因为单纯的一个值的变化在屏幕上是一片空白,不过可以通过监听器来监控动画,添加监听有两种方法,addListener和addUpdateListener,分别对应不同的监听器。
addListener对应的是AnimatorListener监听器,可以使用如下代码添加:
ani.addListener(new AnimatorListener() { @Override public void onAnimationStart(Animator animation) { // TODO Auto-generated method stub //动画开始的时候,此方法被触发 } @Override public void onAnimationRepeat(Animator animation) { // TODO Auto-generated method stub //动画重复的时候,此方法被触发 } @Override public void onAnimationEnd(Animator animation) { // TODO Auto-generated method stub //动画结束的时候,此方法被触发 } @Override public void onAnimationCancel(Animator animation) { // TODO Auto-generated method stub //动画取消的时候,此方法被触发 } });
但是一般情况下,我们并不需要监听这么多状态,所以官方提供了另外一种方式,如下:
ani.addListener(new AnimatorListenerAdapter() { // @Override // public void onAnimationEnd(Animator animation) { // // TODO Auto-generated method stub // super.onAnimationEnd(animation); // //当动画结束的时候,此方法被触发 // } });
AnimatorListenerAdapter是一个AnimatorListener的适配器类,它已经实现了AnimatorListener的所有接口,所以使用它的时候不必将每一个方法都实现,只需要在需要的地方重写就可以了,其他的都会是默认实现。
PS:此类监听器本人习惯称之为状态监听器(有开始、结束、重复、取消等状态)
系统还提供了另外一种监听方法:addUpdateListener,对应的监听器为AnimatorUpdateListener,使用方法如下:
ani.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // TODO Auto-generated method stub float f = (Float)animation.getAnimatedValue(); } });
和上面的状态监听器不同的是,这个AnimatorUpdateListener监听器监听的是动画的实时更新,动画是由很多帧组成了,每播放一帧,onAnimationUpdate方法就会调用一次。
PS:此类监听器本人习惯称为进行时监听器,它监听的是动画的实时播放。
ValueAnimator常用的方法:
ValueAnimator ani = ValueAnimator.ofInt(0,100,200);//对一个int值进行动画过渡 ani.setDuration(3000);//设置动画播放时长,单位为毫秒 ani.setRepeatCount(ValueAnimator.INFINITE);//设置循环次数,-1时则是无限循环,ValueAnimator.INFINITE值就是-1 ani.setRepeatMode(ValueAnimator.REVERSE);//设置循环模式,有两种,RESTRAT重新播放,REVERSE倒序播放 ani.setStartDelay(1000);//延时播放 ani.setEvaluator(new PointEvaluator());//设置自定义估值器 //设置插值器 ani.setInterpolator(new TimeInterpolator() { @Override public float getInterpolation(float input) { // TODO Auto-generated method stub return 0; } });
二、ObjectAnimator对象动画
和ValueAnimator值动画相比,ObjectAnimator对象动画用的就比较多,它的功能相当强大,几乎可以对任何对象的任意属性做动画,用法也很简单,如下:
//从当前位置向左移动300距离再移回来 float currentTranslationX = tv.getTranslationX(); ObjectAnimator ani = ObjectAnimator.ofFloat(tv, "translationX", currentTranslationX,-300f,currentTranslationX); ani.setDuration(2000); ani.start();
上面的方法的第一个参数是目标对象,这里是一个textView,第二个参数是目标对象的目标属性,这里是translationX,后面是若干个属性值。translationX属性控制着控件的X坐标,将一个textView的translationX的属性做动画,X坐标不停的变换,那么整个控件就会产生了动画效果。
属性动画机制其实是不停的给对象(比如View)的某个属性赋值(比如translationX),每一次赋值一般都会触发视图重绘(如果没有那么不会产生动画效果,需要自己手动强制重绘),内部原理其实是:属性动画在改变对象的某个属性的时候(比如属性abc),需要对象提供方法setAbc,这样属性动画就会根据外部传进来的初始值和最终值进行多次调用setAbc方法来给相应的属性赋值,这样在一个时间段内,属性abc被多次改变,越来越接近最终值,如果有触发重绘的话,就会产生动画。
两个注意点:
1、 想要通过属性动画来使对象的某个属性abc进行改变,那么对象就要有setAbc方法,同时,外部传值的时候如果没有初始值,那么对象还需要提供getAbc方法用来获取初始值。
2、 想要有动画的效果,那么对象的属性在改变的时候需要造成UI的改变,否则看不到动画效果。
至于监听器方面,由于ObjectAnimator是继承于ValueAnimator,所以用法和ValueAnimator是一样的,不多说。
三、AnimatorSet 动画集合
真正的项目中的动画都是绚丽多彩的,仅仅靠一个动画很难实现,所以动画集合AnimatorSet也很常用,用法也很简单,如下:
//向左移动 ObjectAnimator ani = ObjectAnimator.ofFloat(tv, "translationX", currentTranslationX,-300f,currentTranslationX); //透明度变换 ObjectAnimator ani1 = ObjectAnimator.ofFloat(tv, "alpha", 1f,0f,1f); //旋转180度 ObjectAnimator ani2 = ObjectAnimator.ofFloat(tv, "rotation", 0f,180f); AnimatorSet as = new AnimatorSet(); as.setDuration(2000); as.play(ani).with(ani1).after(ani2);//先旋转之后,移动和透明度同时改变,with属于同时播放,after和before属于有序播放 as.start();
也可以这样:
ObjectAnimator ani = ObjectAnimator.ofFloat(tv, "translationX", currentTranslationX,-500f,currentTranslationX); ObjectAnimator ani1 = ObjectAnimator.ofFloat(tv, "rotation", 0f,360f); ObjectAnimator ani2 = ObjectAnimator.ofFloat(tv, "alpha", 1f,0f,1f); AnimatorSet as = new AnimatorSet(); //有序进行 // as.playSequentially(ani,ani1,ani2); //同时进行 as.playTogether(ani,ani1,ani2); as.setDuration(3000); as.start();
方法很简单,AnimatorSet动画集合有两种方式,一个就是有序播放,还一个就是同时播放
四、使用xml方式来播放动画
和之前的view动画一样,属性动画也可以写在xml中,方便复用,代码也很简单,在res目录中创建animator文件夹,创建animator.xml文件,内容如下:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="sequentially"> <animator android:duration="2000" android:repeatCount="2" android:valueFrom="100" android:valueTo="300" android:valueType="intType"/> <objectAnimator android:propertyName="translationX" android:duration="3000" android:valueFrom="-500" android:valueTo="0" android:valueType="floatType"></objectAnimator> <set android:ordering="together"> <objectAnimator android:propertyName="rotation" android:valueFrom="0" android:valueTo="180" android:valueType="floatType" android:duration="2000" /> <set android:ordering="sequentially"> <objectAnimator android:propertyName="alpha" android:valueFrom="1" android:valueTo="0" android:valueType="floatType" android:duration="1000"/> <objectAnimator android:duration="1000" android:propertyName="alpha" android:valueFrom="0" android:valueTo="1" android:valueType="floatType"/> </set> </set> </set>
其中animator是ValueAnimator,objectAnimator对应的是ObjectAnimator,Set对应的是动画集合AnimatorSet,set动画集合有一个属性是ordering,两个值,sequentially代表的是有序,together代表同时,其他的代码很简单,就不多做解释了,注意一点,当改动的属性propertyName是颜色的时候,valueType就不需要指定了,系统会自动处理。
使用xml方式的动画可以复用,但是加载会稍微慢一些,而且需要提前知道初始值和结束值并且固定,代码中的动画无法复用,但是加载速度快,初始值和结束值不需要定死,实际使用可以按照需求来选择。
五、TypeEvaluater估值器和TimeInterpolator 时间插值器
1、TypeEvaluater估值器
作用是根据当前属性改变的百分比来计算改变之后的属性值
TypeEvaluater是一个接口,里面只有一个方法,如下:
public interface TypeEvaluator<T> { /** * This function returns the result of linearly interpolating the start and end values, with * <code>fraction</code> representing the proportion between the start and end values. The * calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>, * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>, * and <code>t</code> is <code>fraction</code>. * * @param fraction The fraction from the starting to the ending values * @param startValue The start value. * @param endValue The end value. * @return A linear interpolation between the start and end values, given the * <code>fraction</code> parameter. */ public T evaluate(float fraction, T startValue, T endValue); }
这个方法有三个参数,第一个参数是浮点类型fraction,意味着当前属性改变的百分比,后面两个参数代表这初始对象和终止对象,通过一系列算法最后返回一个同样的对象,这个返回的对象就是当前瞬间的状态,拿系统提供的IntegerEvaluator为例
public class IntEvaluator implements TypeEvaluator<Integer> { public Integer evaluate(float fraction, Integer startValue, Integer endValue) { int startInt = startValue; return (int)(startInt + fraction * (endValue - startInt)); } }
这里面的对象就是一个整形,传进去的三个参数中,结束值减去初始值就是整个的变化区间,乘以当前的属性改变百分比,就是当前变化的值,再加上初始值返回,即当前瞬间的值。
初始值和结束值肯定是外部传进去的,那么第一个参数fraction(属性改变的百分比)是从哪里得到的呢,其实是从TimeInterpolator时间插值器中得到的。
2、TimeInterpolator时间插值器
作用是根据时间变化百分比来计算当前属性改变的百分比
同样,先看看接口
public interface TimeInterpolator { /** * Maps a value representing the elapsed fraction of an animation to a value that represents * the interpolated fraction. This interpolated value is then multiplied by the change in * value of an animation to derive the animated value at the current elapsed animation time. * * @param input A value between 0 and 1.0 indicating our current point * in the animation where 0 represents the start and 1.0 represents * the end * @return The interpolation value. This value can be more than 1.0 for * interpolators which overshoot their targets, or less than 0 for * interpolators that undershoot their targets. */ float getInterpolation(float input); }
接口方法也很简单,只有一个方法,方法中的参数input是从系统中获得,这个参数的值随着动画的运行不断变化,并且是匀速变化,可以理解为“时间”,时间流逝是匀速的,这里面就是根据时间流逝百分比来计算属性变化的百分比,返回一个瞬时的浮点型,这个浮点型就是估值器中的fraction。
流程:动画开始–>插值器算法通过时间流逝得到属性变化百分比fraction–>估值器算法通过属性变化百分比得到当前属性值–>动画结束。
常用的系统提供的插值器有:
LinearInterpolator线性插值器(匀速变化)、AccelerateDecelerateIntepolator加速减速插值器、
AccelerateIntepolator加速插值器和DecelerateIntepolator减速插值器等,如果要自定义插值器就需要实现Interpolator或者TimeInterpolator。
常用的系统提供的估值器有:
FloatEvaluator浮点估值、IntEvaluator整形估值、ArgbEvaluator颜色估值器,如果自定义估值器的话就需要实现TypeEvaluator。
六、对任意属性做动画
前面说属性动画原理机制的时候提到过,要想有动画效果,需要两个注意点:
1、 想要通过属性动画来使对象的某个属性abc进行改变,那么对象就要有setAbc方法,同时,外部传值的时候如果没有初始值,那么对象还需要提供getAbc方法用来获取初始值。
2、 想要有动画的效果,那么对象的属性在改变的时候需要造成UI的改变,否则看不到动画效果。
那么如果想要给某个对象做动画,但是对象并没有提供相应的setAbc方法,或者相应的setAbc方法并没有达到想要的效果,比如TextView的setWidtht方法,并不是控制了View的宽度,而是最小和最大宽度,所以这种情况下,就需要自己想办法。
分析要想达到的效果是:宽度不停的变化从而产生动画。
有两种方法可以实现:
1、 对目标对象进行包装,定义set和get方法,在set方法内进行目标对象的属性变化并且更新UI
例如:
private class ViewHolder{ private TextView tv; public ViewHolder(TextView tv){ this.tv = tv; } public void setWidth(int width){ tv.getLayoutParams().width = width; tv.requestLayout(); } public int getWidth(){ return tv.getLayoutParams().width; } public void setHeight(int height){ tv.getLayoutParams().height = height; tv.requestLayout(); } public int getHeight(){ return tv.getLayoutParams().height; } }
在外部调用的时候就需要如此写即可
public void startAnimation(){ ViewHolder viewHolder = new ViewHolder(tv); ObjectAnimator ani = ObjectAnimator.ofInt(viewHolder, "width", 500).setDuration(3000); ani.start(); }
2、 ValueAnimator类中可以添加进行时监听器addUpdateListener,监听每一帧的变化,并且每一帧都会调用,那么直接在方法内添加对对象属性的改变并且重新绘制即可,这样就会在每一帧的时候变化对象的属性,继而产生动画。如下:
public void startAnimation(){ // ViewHolder viewHolder = new ViewHolder(tv); // ObjectAnimator ani = ObjectAnimator.ofInt(viewHolder, "width", 500).setDuration(3000); // ani.start(); ValueAnimator ani = ValueAnimator.ofFloat(0,1); ani.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // TODO Auto-generated method stub float f = animation.getAnimatedFraction(); Log.v("Animator", "属性改变百分比是:"+f); tv.getLayoutParams().height = (int)(f*500); tv.requestLayout(); } }); ani.setDuration(3000); ani.start(); }
这个其实就是利用了监听器,进行时监听器监听的是动画的实时播放,所以在方法内做属性的改变,每一帧调用一次,整体就形成了动画…
PS:总感觉类似于“挂载”?
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件