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

Android属性动画

2016-03-18 19:22 465 查看
前言:

android动画分三类:一是View 动画,又叫Tween动画,二是frame 动画(帧动画),又叫drawable 动画,三是属性动画,即property animation.

View动画,根据作用又分为缩放动画ScaleAnimation/移位动画TranslateAnimation / 透明度动画AlphaAnimation / 旋转动画RotateAnimation,这四个动画都继承android.view.animation下的Animation类。继承Animation的除了这四个类外,还有AnimationSet.

帧动画 对应AnimationDrawable类,继承自DrawableContainer,通过加载多个Drawable来一帧一帧播放达到动画效果。尽管很多人觉得这个不值一提,但是某些动画效果,如显示个小羊吃草还必须得用这个动画。

接下来进入正题谈属性动画,该动画从android3.0引入,API11引入,是为了弥补view动画的不足。正式项目里用的话为了兼容android2.3可以用NineOldAndroids,直接将生成的jar包放进去就ok了。

View动画,包名android.view.animation,基类为Animation,核心子类为TranslateAnimation,ScaleAnimation,AlphaAnimation,RotateAnimation及AnimationSet。

Property动画,包名android.animation,基类为Animator,核心子类为AnimatorSet,ValueAnimator,ObjectAnimator,TimeAnimator.

view 动画+updateParams 约等于property动画效果。但是切忌,使用view动画+updateParams策略时,务必注意不要使用transAnim.setFillAfter(true)

如果想改变动画后view的属性,如位置,可以用属性动画也可以用view动画+updateParams,当然前者更省事。在有些情况下,仅仅是想得到动画的呈现,动画结束后的位置就是view的初始位置,如view从一个地方飞过来,动画结束时view的位置就是view的位置时,此时view动画最合适!

> 三种动画:View动画、帧动画、属性动画:

1. View animation只能应用于View对象,而且只支持一部分属性,渐变动画只支持四种类型:平移(Translate)、旋转(Rotate)、缩放(Scale)、不透明度(Alpha)。

2. Frame动画,传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影补间动画和帧动画。

3. 属性动画要求动画作用的对象提供该属性的get和set方法,属性动画根据你传递的该熟悉的初始值和最终值,以动画的效果多次去调用set方法,每次传递给set方法的值都不一样,确切来说是随着时间的推移,所传递的值越来越接近最终值。总结一下,你对object的属性xxx做动画,如果想让动画生效,要同时满足两个条件:

1. object必须要提供setXxx方法,如果动画的时候没有传递初始值,那么还要提供getXxx方法,因为系统要去拿xxx属性的初始值(如果这条不满足,程序直接Crash)

2. object的setXxx对属性xxx所做的改变必须能够通过某种方法反映出来,比如会带来ui的改变啥的(如果这条不满足,动画无效果但不会Crash)

属性动画不仅兼容视图动画,还能解决许多视图动画无法解决的问题,可以看做更加广义的动画。属性动画框架在Android3.0中引入,是一个健壮的框架,它几乎可以把任何对象变成动画。属性动画的目标与宗旨是:能够根据时间的推移来实时改变任何对象的属性值,而不用关心该对象是否要绘制在屏幕上。属性动画框架主要包含几个部分:动画执行类、动画监听机类、计算估值器、动画插值器.

ValueAnimator、ObjectAnimator、AnimatorSet。ValueAnimator是最常用的属性动画时间引擎,ValueAnimator本身不作用于任何对象,主要用于对一个值做动画,根据当前动画进度提供计算值,至于如何利用这个值,则完全不关心。ObjectAnimator:顾名思义,是面向对象的ValueAnimator,需要指定特定的操作对象及相应属性,这样Android系统便可以自动更新对象的属性。AnimatorSet是属性动画集合,主要用于整合多个动画,比如先后执行、并发执行等.

>属性动画工作原理:

创建属性动画时,每个对象都包含一个ValueAnimator,并通过监控机制AnimatorUpdateListner实时监控动画的执行,并可以计算出运行了多场时间、当前相应属性的值等,比如(X),之后,可以根据需求更新相应的对象。最直观的就是利用ObjectAnimator做动画时,目标对象需要提供相应属性的getter和setter方法,系统会根据属性的初始值和最终值,以动画的效果多次去调用set方法,随着时间的推移,set的值会越来越接近最终值。

> Android动画进阶—使用开源动画库nineoldandroids。

/**

Makes the TextView exactly this many pixels wide.

You could do the same thing by specifying this number in the LayoutParams.

@see #setMaxWidth(int)

@see #setMinWidth(int)

@see #getMinWidth()

@see #getMaxWidth()

@attr ref android.R.styleable#TextView_width

*/

@android.view.RemotableViewMethod

public void setWidth(int pixels) {

mMaxWidth = mMinWidth = pixels;

mMaxWidthMode = mMinWidthMode = PIXELS;

requestLayout();

invalidate();

}

/**

Return the width of the your view.

@return The width of your view, in pixels.

*/

@ViewDebug.ExportedProperty(category= layout)

public final int getWidth() {

return mRight - mLeft;

}

总之,TextView和Button的setWidth和getWidth干的不是同一件事情,通过setWidth无法改变控件的宽度,所以对width做属性动画没有效果,对应于属性动画的两个条件来说,本例中动画不生效的原因是只满足了条件1未满足条件2。

针对上述问题,Google告诉我们有3中解决方法:

1. 给你的对象加上get和set方法,如果你有权限的话

2. 用一个类来包装原始对象,间接为其提供get和set方法

3. 采用ValueAnimator,监听动画过程,自己实现属性的改变

》 Button500S从1到100

private void performAnimate(finalView target, final int start, final int end) {

ValueAnimator valueAnimator = ValueAnimator.ofInt(1,100);

valueAnimator.addUpdateListener(newAnimatorUpdateListener() {

//持有一个IntEvaluator对象,方便下面估值的时候使用

private IntEvaluator mEvaluator = new IntEvaluator();

@Override

public void onAnimationUpdate(ValueAnimator animator) {

//获得当前动画的进度值,整型,1-100之间

int currentValue = (Integer)animator.getAnimatedValue();

Log.d(TAG,current value: + currentValue);

//计算当前进度占整个动画过程的比例,浮点型,0-1之间

float fraction = currentValue / 100f;

//直接调用整型估值器通过比例计算出宽度,然后再设给Button

target.getLayoutParams().width = mEvaluator.evaluate(fraction, start, end);

target.requestLayout();

}

});

valueAnimator.setDuration(5000).start();

}

@Override

public void onClick(View v) {

if(v == mButton) {

performAnimate(mButton,mButton.getWidth(), 500);

}

}

>可以控制速度,即为Interpolator(插值),有以下几种(Interpolator的实现类):

LinearInterpolator(匀速);AccelerateInterpolator(先慢后快);

AccelerateDecelerateInterpolator(先慢中快后慢);DecelerateInterpolator(先快后慢);

CycleInterpolator(循环播放,速度为正弦曲线);AnticipateInterpolator(先回撤,再匀速向前);

OvershootInterpolator(超过,拉回);BounceInterpolator(回弹);

> 属性动画继承关系:Animator(属性动画的基类)→ValueAnimator→ObjectAnimator如何使用:

1.调用ObjectAnimator的静态工厂方法创建动画(ofInt、ofFloat、ofObject)

2.调用SetXxx()设置动画持续时间、插值方式、重复次数等。

3.监听事件

4.调用Animator对象的start()方法启动动画

//标准示范,单个动画属性(ObjectAnimator)执行

public void move1(View view){

//直接调用ObjectAnimator的工厂方法(静态方法),可以创建ObjectAnimator实例

//前2个参数分别要指定:操作的具体的对象、操作的对象的属性。本例中,具体对象为ImageView,属性为X轴位移

//第3个参数,是操作的对象的属性,其动画变化的范围的。本例中,X轴位移:0f~200f

ObjectAnimator.ofFloat(mImageView, "translationX", 0f,200f)

.setDuration(2000)

.start();

}

//同一个对象设置多个属性动画,会同时执行。可见,属性动画实例调用start方法后,是一个异步的过程

public void move2(View view){

ObjectAnimator.ofFloat(mImageView, "translationX", 0f,200f).setDuration(2000).start();

ObjectAnimator.ofFloat(mImageView, "translationY", 0f,200f).setDuration(2000).start();

ObjectAnimator.ofFloat(mImageView, "rotation", 0f,360f).setDuration(2000).start();

}

//(多个动画同时时推荐),使用PropertyValuesHolder,先将多个属性动画hold住,再一起开启动画,可以实现同样的效果。如此做法对动画进行了优化,使用多个属性的时候,更加节省系统资源。

public void move3(View view){

PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("translationX", 0f,200f);

PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("translationY", 0f,200f);

PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat("rotation", 0f,360f);

ObjectAnimator.ofPropertyValuesHolder(mImageView, p1,p2,p3).setDuration(2000).start();

}

//(多个动画需求不同时时推荐),利用AnimatorSet,组合多个Animation,可以对多个动画属性进行顺序控制

//同时执行:set.playTogether(animator1,animator2,animator3)

//顺序执行:set.playSequentially(animator1,animator2,animator3)

//分布执行:play().with(); play().after();

public void move4(View view){

ObjectAnimator animator1 = ObjectAnimator.ofFloat(mImageView, "translationX", 0f,200f);

ObjectAnimator animator2 = ObjectAnimator.ofFloat(mImageView, "translationY", 0f,200f);

ObjectAnimator animator3 = ObjectAnimator.ofFloat(mImageView, "rotation", 0f,360f);

AnimatorSet set = new AnimatorSet();

set.play(animator1).with(animator2);

set.play(animator3).after(animator1);

set.setDuration(1000).start();

}

> 从属性动画框架可以知:想要合理的使用属性动画,必须正确的利用动画的几大元素:动画执行类、动画监听、估值器、插值器,合理的属性动画工具能够帮助我们更加方便的达成目标。

1) 利用ValueAnimator实现属性动画:

第一步:通过 ValueAnimator静态方法获取对象ofInt(), ofFloat(),or ofObject().,并设置动画持续时长。

ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);

animation.setDuration(1000);

第二步:设置实时监听。ValueAnimator.AnimatorUpdateListener并实现其onAnimationUpdate() 。在该函数中,可以获取动画进度、以及属性的实时值,但该实时值并未直接作用于任何对象,如果想要作用于某个对象,必须用于将属性值实时设置到对象。 在onAnimationUpdate() 内部,可以通过 getAnimatedValue(). 获取当前计算到的值,之后通过对象的set等方法,实时更新对象,比如 setAlpha() 等:

animation.addUpdateListener(new AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animator) {

float currentValue = (Integer)animator.getAnimatedValue();

//计算当前进度占整个动画过程的比例,浮点型,0-1之间 然后再设给Object(比如View)

targetView.setAlpha(currentValue );

}

});

第三步:执行动画,之后ValueAnimator 就开始利用估值器已经插值器计算属性值,并实时利用监听接口更新对象。

animation.start();

2) 利用ObjectAnimator实现属性动画

第一步:利用ObjectAnimator静态方法构造对象,同时要制定target对象、以及要操作的属性,比如:不透明度(alpha):

ObjectAnimator anim = ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f);

anim.setDuration(1000);

第二步:执行动画

anim.start();

但是,由于ObjectAnimator会利用对象的setter方法自动更新相应的属性,该对象必须具有setter方法,如果实现动画的时候没有传递初始值,那么还要提供getter方法,否则无法更新。例如:属性是color,则必须具有setterColor/getterColor方法,否则动画无效。如果不存在相应属性的操作方法,则可以通过wrapper 方式间接为其提供getter和setter方法。例如:View没有直接设置宽度的方法width,可以利用wrapper实现setWidth,getWidth:

public class ViewWrapper {

private View mTarget;

public ViewWrapper(View target) {

mTarget = target;

}

public int getWidth() {

return mTarget.getLayoutParams().width;

}

public void setWidth(int width) {

mTarget.getLayoutParams().width = width;

mTarget.requestLayout();

} }

之后便可使用该封装类进行属性动画:

private void performAnimate(View view) {

ViewWrapper wrapper = new ViewWrapper(view);

ObjectAnimator.ofInt(wrapper, "width", 500).setDuration(5000).start();

}

3) 利用AnimatorSet实现属性动画

开发中,经常会遇到这种情形:播放一个动画依赖另一个动画是否播放完成。在属性动画中框架中,可以利用AnimatorSet构造属性动画集,来整合多个动画的播放,控制动画的并发、顺序逻辑等。AnimatorSet是Animator的子类,不仅可以作为动画使用,而且可以实现嵌套。使用方法:

ObjectAnimator anim1= ObjectAnimator.ofFloat(foo, "alpha" …);

ObjectAnimator anim2= ObjectAnimator.ofFloat(foo, "x" …);

ObjectAnimator anim3= ObjectAnimator.ofFloat(foo, "y" … );

ObjectAnimator anim4= ObjectAnimator.ofFloat(foo, …);

ObjectAnimator anim5= ObjectAnimator.ofFloat(foo, …);

AnimatorSet bouncer = new AnimatorSet();

bouncer.play(anim1).before(anim2);

bouncer.play(anim2).with(anim3);

bouncer.play(anim3).with(anim4);

bouncer.play(bounceBackAnim).after(stretchAnim2);

//集合与元素的嵌套使用

AnimatorSet animatorSet = new AnimatorSet();

animatorSet.play(bouncer).before(anim5);

animatorSet.start();

}

4) 利用LayoutTransition 实现布局属性动画:

属性动画允许布局通过动画来显示变化,比如新View元素添加到LinearLayout中时,新元素可以定义显示动画,旧元素可以定义移动动画,布局动画更像是childViews属性动画集。布局属性动画主要包含以下几种元素:

o APPEARING 新添加的View本身的出现动画;

o DISAPPEARING View消失动画;

o CHANGE_APPEARING 由于新增了其他View而需要改变位置的动画;

o CHANGE_DISAPPEARING 由于移除了其他View而需要改变位置的动画。

private void setupTransition(LayoutTransition transition) {

customDisappearingAnim = ObjectAnimator.ofFloat(null, "rotationX", 0f, 90f)

customAppearingAnim = ObjectAnimator.ofFloat(null, "rotationY", 90f, 0f)

transition.setAnimator(LayoutTransition.DISAPPEARING, customDisappearingAnim);

transition.setAnimator(LayoutTransition.CHANGE_APPEARING, customChangingAppearingAnim);

transition.setAnimator(LayoutTransition. APPEARING , customAnimCB);

transition.setAnimator(LayoutTransition.CHANGE_APPEARING, customChangingAppearingAnim);

}

5) 利用XML实现属性动画。

同视图动画类似,属性动画也可利用XML定义,不过放置的位置与视图动画不同,属性动画的XML文件放在res/animator目录下。XML属性动画的使用分两步

第一步:定义相应动画

<set android:ordering="sequentially">

<set>

<objectAnimator

android:propertyName="x"

android:duration="500"

android:valueTo="400"

android:valueType="intType"/>

<objectAnimator

android:propertyName="y"

android:duration="500"

android:valueTo="300"

android:valueType="intType"/>

</set>

<objectAnimator

android:propertyName="alpha"

android:duration="500"

android:valueTo="1f"/>

</set>

第二步:在Java代码中利用AnimatorInflater加载,渲染既可

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.anim.property_animator);

set.setTarget(myObject);

set.start();

属性动画总结

属性动画与视图动画最大的区别是:属性动画能够实时改变Object的属性,而视图动画无法做到,并且属性动画应用的范围更广,限制更小。很多场合下,如果视图动画无法满足需求,不放考虑属性动画,然而功能的强大导致了实现的复杂度提升,所以如果视图动画足够满足需求,可以不用视图动画。

动画的应用:http://www.mamicode.com/info-detail-1150209.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: