配色: 字号:
Android动画完全解析--View动画
2017-01-18 | 阅:  转:  |  分享 
  
Android动画完全解析--View动画



一、View动画





1、常见的4中View动画:AlphaAnimation、ScaleAnimation、TranslateAnimation、RotateAnimation



使用动画的方式有两种:一种是xml形式、另一种是Java代码。使用起来都比较简单。还有一种AnimationSet,它是动画集合,将几种动画合在一起使用,下面AnimationSet来写动画。



创建缩放/透明动画





//创建AnimationSet对象

aSet=newAnimationSet(false);

//创建动画对象

sAnim=newScaleAnimation(1,0.5f,1,0.5f);

//设置动画执行时间

sAnim.setDuration(3000);

//添加动画到集合中

aSet.addAnimation(sAnim);

aAnim=newAlphaAnimation(1,0.5f);

aAnim.setDuration(3000);

aSet.addAnimation(aAnim);

aSet.start();

btn_sys.setAnimation(aSet);



就这样,完成了一个动画集合的小例子,其它几种动画的使用方法类似。



2.View动画的源码分析



分析源码之前,我们需要知道这4种动画其实都是Animation的子类,而如果想要实现动画效果,则必须重写applyTransformation()方法,这点可以从这个方法的注释可以看出。





/

HelperforgetTransformation.Subclassesshouldimplementthistoapply

theirtransformsgivenaninterpolationvalue.Implementationsofthis

methodshouldalwaysreplacethespecifiedTransformationordocument

theyaredoingotherwise.



@paraminterpolatedTimeThevalueofthenormalizedtime(0.0to1.0)

afterithasbeenrunthroughtheinterpolationfunction.

@paramtTheTransformationobjecttofillinwiththecurrent

transforms.

/

protectedvoidapplyTransformation(floatinterpolatedTime,Transformationt){

}



OK,这里我们分析ScaleAnimation,其它三个可以自行分析。



ScaleAnimation



首先,我们看下构造函数





publicScaleAnimation(floatfromX,floattoX,floatfromY,floattoY,

floatpivotX,floatpivotY){

mResources=null;

mFromX=fromX;

mToX=toX;

mFromY=fromY;

mToY=toY;



mPivotXType=ABSOLUTE;

mPivotYType=ABSOLUTE;

mPivotXValue=pivotX;

mPivotYValue=pivotY;

initializePivotPoint();

}



源码很简单,只是将传递过来的变量赋值,然后调用initializePivotPoint()方法





privatevoidinitializePivotPoint(){

if(mPivotXType==ABSOLUTE){

mPivotX=mPivotXValue;

}

if(mPivotYType==ABSOLUTE){

mPivotY=mPivotYValue;

}



在构造函数执行完之后,马上就会执行initialize(),获取缩放中心点坐标





@Override

publicvoidinitialize(intwidth,intheight,intparentWidth,intparentHeight){

super.initialize(width,height,parentWidth,parentHeight);



mFromX=resolveScale(mFromX,mFromXType,mFromXData,width,parentWidth);

mToX=resolveScale(mToX,mToXType,mToXData,width,parentWidth);

mFromY=resolveScale(mFromY,mFromYType,mFromYData,height,parentHeight);

mToY=resolveScale(mToY,mToYType,mToYData,height,parentHeight);



mPivotX=resolveSize(mPivotXType,mPivotXValue,width,parentWidth);

mPivotY=resolveSize(mPivotYType,mPivotYValue,height,parentHeight);



紧接着,当调用animation.start()方法,





publicvoidsetStartTime(longstartTimeMillis){

mStartTime=startTimeMillis;

mStarted=mEnded=false;

mCycleFlip=false;

mRepeated=0;

mMore=true;

}



/

Conveniencemethodtostarttheanimationthefirsttime

{@link#getTransformation(long,Transformation)}isinvoked.

/

publicvoidstart(){

setStartTime(-1);

}



这个只是开启设置下时间,重要的是view.setAnimation()这个方法。如果上面的例子代码不书写view.setAnimation(),则不会出现动画效果,而如果书写.start()方法则依然可以执行,只不过再第二次执行时候的是在第一次执行的基础上,不是我们想要的结果。看源码





/

Setsthenextanimationtoplayforthisview.

Ifyouwanttheanimationtoplayimmediately,use

{@link#startAnimation(android.view.animation.Animation)}instead.

Thismethodprovidesallowsfine-grained

controloverthestarttimeandinvalidation,butyou

mustmakesurethat1)theanimationhasastarttimeset,and

2)theview''sparent(whichcontrolsanimationsonitschildren)

willbeinvalidatedwhentheanimationissupposedto

start.



@paramanimationThenextanimation,ornull.

/

publicvoidsetAnimation(Animationanimation){

mCurrentAnimation=animation;



if(animation!=null){

//Ifthescreenisoffassumetheanimationstarttimeisnowinsteadof

//thenextframewedraw.KeepingtheSTART_ON_FIRST_FRAMEstarttime

//wouldcausetheanimationtostartwhenthescreenturnsbackon

if(mAttachInfo!=null&&!mAttachInfo.mScreenOn&&

animation.getStartTime()==Animation.START_ON_FIRST_FRAME){

animation.setStartTime(AnimationUtils.currentAnimationTimeMillis());

}

animation.reset();

}

}



从注释中可以看出,和start方法调用的是同一个方法。接着执行的是applyTransformation()这个方法,此方法是自行实现的,而且冲该方法的注释可以看出这个方法是是HelperforgetTransformation.查看getTransformation()





/

Getsthetransformationtoapplyataspecifiedpointintime.Implementationsofthis

methodshouldalwaysreplacethespecifiedTransformationordocumenttheyaredoing

otherwise.



@paramcurrentTimeWhereweareintheanimation.Thisiswallclocktime.

@paramoutTransformationAtransformationobjectthatisprovidedbythe

callerandwillbefilledinbytheanimation.

@returnTrueiftheanimationisstillrunning

/

publicbooleangetTransformation(longcurrentTime,TransformationoutTransformation){

if(mStartTime==-1){

mStartTime=currentTime;

}



finallongstartOffset=getStartOffset();

finallongduration=mDuration;

floatnormalizedTime;

if(duration!=0){

normalizedTime=((float)(currentTime-(mStartTime+startOffset)))/

(float)duration;

}else{

//timeisastep-changewithazeroduration

normalizedTime=currentTime
}



finalbooleanexpired=normalizedTime>=1.0f;

mMore=!expired;



if(!mFillEnabled)normalizedTime=Math.max(Math.min(normalizedTime,1.0f),0.0f);



if((normalizedTime>=0.0f||mFillBefore)&&(normalizedTime<=1.0f||mFillAfter)){

if(!mStarted){

fireAnimationStart();

mStarted=true;

if(USE_CLOSEGUARD){

guard.open("cancelordetachorgetTransformation");

}

}



if(mFillEnabled)normalizedTime=Math.max(Math.min(normalizedTime,1.0f),0.0f);



if(mCycleFlip){

normalizedTime=1.0f-normalizedTime;

}



finalfloatinterpolatedTime=mInterpolator.getInterpolation(normalizedTime);

applyTransformation(interpolatedTime,outTransformation);

}



if(expired){

if(mRepeatCount==mRepeated){

if(!mEnded){

mEnded=true;

guard.close();

fireAnimationEnd();

}

}else{

if(mRepeatCount>0){

mRepeated++;

}



if(mRepeatMode==REVERSE){

mCycleFlip=!mCycleFlip;

}



mStartTime=-1;

mMore=true;



fireAnimationRepeat();

}

}



if(!mMore&&mOneMoreTime){

mOneMoreTime=false;

returntrue;

}



returnmMore;

}



这个方法中有一个特别重要的代码:applyTransformation(interpolatedTime,outTransformation);故它会调用applyTransformation方法来通过矩阵实现变换。



上面整体分析了Animation的执行流程,现在就具体来分析下ScaleAnimation是怎么做到缩放的。其实整个缩放动画一共就不到300行代码,而真正起决定作用的又只有几十行代码。





@Override

protectedvoidapplyTransformation(floatinterpolatedTime,Transformationt){

floatsx=1.0f;

floatsy=1.0f;

floatscale=getScaleFactor();



if(mFromX!=1.0f||mToX!=1.0f){

sx=mFromX+((mToX-mFromX)interpolatedTime);

}

if(mFromY!=1.0f||mToY!=1.0f){

sy=mFromY+((mToY-mFromY)interpolatedTime);

}



if(mPivotX==0&&mPivotY==0){

t.getMatrix().setScale(sx,sy);

}else{

t.getMatrix().setScale(sx,sy,scalemPivotX,scalemPivotY);

}



由源码可知最后动画还是通过矩阵变换来实现的。这里的interpolatedTime表示差值器,这个概念后面会提到,首先,获取缩放比例,然后,再根据不同时间段获取不同的sx值,最后通过矩阵变换来设置。其实这个方法是会和前面提到过的getTransformation()这个方法一起执行起作用的,两个方法一直执行都动画结束。下面将会写一个Demo来演示这点。



3.自定义一个动画



前面使用AnimationSet将ScaleAnimation和AlphaAnimation结合起来,那么我们可不可以自定义一个Animation来实现这个效果呢?答案是肯定的。



a.首先,继承Animation





publicclassScaleAndAlphaAnimationextendsAnimation



b.接着就是利用构造函数将需要的参数传递进来





publicScaleAndAlphaAnimation(floatfromX,floattoX,floatfromY,floattoY,floatfromAlpha,floattoAlpha){

this.mFromX=fromX;

this.mFromY=fromY;

this.mToX=toX;

this.mToY=toY;

this.mFromAlpha=fromAlpha;

this.mToAlpha=toAlpha;

System.out.println("ScaleAndAlphaAnimation.ScaleAndAlphaAnimation()");

}



c.最后就是复写applyTransformation方法了,这里我是参照ScaleAnimation和AlphaAnimation源码来写的





@SuppressLint("NewApi")@Override

protectedvoidapplyTransformation(floatinterpolatedTime,Transformationt){

//缩放动画设置

floatsx=1.0f;

floatsy=1.0f;

floatscale=getScaleFactor();

if(mFromX!=1.0f||mToX!=1.0f){

sx=mFromX+((mToX-mFromX)interpolatedTime);

}

if(mFromY!=1.0f||mToY!=1.0f){

sy=mFromY+((mToY-mFromY)interpolatedTime);

}

t.getMatrix().setScale(sx,sy);

//透明度动画设置

finalfloatalpha=mFromAlpha;

t.setAlpha(alpha+((mToAlpha-alpha)interpolatedTime));

System.out.println("ScaleAndAlphaAnimation.applyTransformation()");

//这在scaleanimation源码中代表缩放中心掉的位置

//if(mPivotX==0&&mPivotY==0){

//t.getMatrix().setScale(sx,sy);

//}

//else{

//t.getMatrix().setScale(sx,sy,scalemPivotX,scalemPivotY);

//}

}



全部代码







publicclassScaleAndAlphaAnimationextendsAnimation{



privatefloatmFromX;

privatefloatmFromY;

privatefloatmToX;

privatefloatmToY;

privatefloatmFromAlpha;

privatefloatmToAlpha;

//缩放比例

privatefloatscale=1;



publicScaleAndAlphaAnimation(floatfromX,floattoX,floatfromY,floattoY,floatfromAlpha,floattoAlpha){

this.mFromX=fromX;

this.mFromY=fromY;

this.mToX=toX;

this.mToY=toY;

this.mFromAlpha=fromAlpha;

this.mToAlpha=toAlpha;

System.out.println("ScaleAndAlphaAnimation.ScaleAndAlphaAnimation()");

}



@SuppressLint("NewApi")@Override

protectedvoidapplyTransformation(floatinterpolatedTime,Transformationt){

//缩放动画设置

floatsx=1.0f;

floatsy=1.0f;

floatscale=getScaleFactor();

if(mFromX!=1.0f||mToX!=1.0f){

sx=mFromX+((mToX-mFromX)interpolatedTime);

}

if(mFromY!=1.0f||mToY!=1.0f){

sy=mFromY+((mToY-mFromY)interpolatedTime);

}

t.getMatrix().setScale(sx,sy);

//透明度动画设置

finalfloatalpha=mFromAlpha;

t.setAlpha(alpha+((mToAlpha-alpha)interpolatedTime));

System.out.println("ScaleAndAlphaAnimation.applyTransformation()");

//这在scaleanwww.tt951.comimation源码中代表缩放中心掉的位置

//if(mPivotX==0&&mPivotY==0){

//t.getMatrix().setScale(sx,sy);

//}

//else{

//t.getMatrix().setScale(sx,sy,scalemPivotX,scalemPivotY);

//}

}





@Override

publicbooleangetTransformation(longcurrentTime,

TransformationoutTransformation){

System.out.println("ScaleAndAlphaAnimation.getTransformation()");

returnsuper.getTransformation(currentTime,outTransformation);

}



@SuppressLint("NewApi")@Override

protectedfloatgetScaleFactor(){

return0.5f;

}





@Override

publicvoidinitialize(intwidth,intheight,intparentWidth,

intparenwww.baiyuewang.nettHeight){

super.initialize(width,height,parentWidth,parentHeight);

System.out.println("ScaleAndAlphaAnimation.initialize()");

}

}



log输出如下:从这里可以看出,这几个方法执行的顺序是

构造函数–>initialize()–>接着就是applyTransformation()和getTransformation()的重复执行到动画结束了。(先applyTransformation()后getTransformation())





07-1206:42:57.958:I/System.out(4992):ScaleAndAlphaAnimation.ScaleAndAlphaAnimation()

07-1206:42:57.958:I/System.out(4992):ScaleAndAlphaAnimation.initialize()

07-1206:42:57.958:I/System.out(4992):ScaleAndAlphaAnimation.applyTransformation()

07-1206:42:57.958:I/System.out(4992):ScaleAndAlphaAnimation.getTransformation()

07-1206:42:57.958:I/System.out(4992):ScaleAndAlphaAnimation.applyTransformation()

07-1206:42:57.968:I/System.out(4992):ScaleAndAlphaAnimation.getTransformation()

07-1206:42:57.968:I/System.out(4992):ScaleAndAlphaAnimation.applyTransformation()

07-1206:42:57.998:I/System.out(4992):ScaleAndAlphaAnimation.getTransformation()

07-1206:42:57.998:I/System.out(4992):ScaleAndAlphaAnimation.applyTransformation()

07-1206:42:58.028:I/System.out(4992):ScaleAndAlphaAnimation.getTransformation()



OK,这篇就介绍到这里,下篇继续分析动画。

献花(0)
+1
(本文系thedust79首藏)