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
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
相关文章推荐
- Android通讯录数据库介绍与基本操作(增删改查)
- Android系统将内置滤镜功能
- Android 知识体系
- android socket实现文件导出功能
- 搭建高质量的Android项目框架系列四
- 关于SQLite在Android开发中的知识点总结
- Android 线程模型
- 复习android 的大喇叭~~~
- 搭建高质量的Android项目框架系列三
- Android遇到No external storage available
- 搭建高质量的Android项目框架系列二
- bug_ _ android.view.WindowManager$BadTokenException: Unable to add window -- token
- Android 的画布Canvas和画笔Paint
- android日志打印代码 logcat
- 搭建高质量的Android项目框架系列一
- Android Studio Gradle Configuration Errors总结
- Android Studio Gradle Configuration Errors总结
- Android Studio Gradle Configuration Errors总结
- Android 官方分辨率详解
- Android之EventBus使用详解