Android动画知识汇总

  本文是对Android动画的汇总关于Android的动画包括 3.0之前的View Animation,3.0之后的 Property Animator 以及5.0新增的(Touch feedback(触摸反馈)Reveal effect(揭露效果)Activity transitions(Activity转换效果)Curved motion(曲线运动)View state changes (视图状态改变)Animate Vector Drawables(可绘矢量动画))6种动画。


几种动画的详细内容如下:

  1. View Animation :

     第一类是Tween动画,就是对场景里的对象不断的进行图像变化来产生动画效果。 

       第二类就是 Frame动画,即顺序的播放事先做好的图像,与gif图片原理类似。


       下面就讲一下Tweene Animations。

        主要类:

          Animation   动画

          AlphaAnimation 渐变透明度

          otateAnimation 画面旋转

          ScaleAnimation 渐变尺寸缩放

          ranslateAnimation 位置移动

          AnimationSet  动画集


      以自定义View为例,该View很简单,画面上只有一个图片。 现在我们要对整个View分别实现各种Tween动画效果。 

      1) AlphaAnimation实现代码:  

1
2
3
4
5
       //初始化  
       Animation alphaAnimation =  new  AlphaAnimation( 0 .1f,  1 .0f);  
       //设置动画时间           
       alphaAnimation.setDuration( 3000 );  
       this .startAnimation(alphaAnimation);


        其中AlphaAnimation类第一个参数fromAlpha表示动画起始时的透明度, 第二个参数toAlpha表示动画结束时的透明度。setDuration用来设置动画持续时间。

       fromAlpha、toAlpha属性说明:0.0表示完全透明 1.0表示完全不透明 以上值取0.0-1.0之间的float数据类型的数字

    

      2) RotateAnimation实现代码:

1
2
3
       Animation rotateAnimation =  new  RotateAnimation(0f, 360f);  
       rotateAnimation.setDuration( 1000 );  
       this .startAnimation(rotateAnimation);


      其中RotateAnimation类第一个参数fromDegrees表示动画起始时的角度, 第二个参数toDegrees表示动画结束时的角度。另外还可以设置伸缩模式pivotXType、pivotYType, 伸缩动画相对于x,y 坐标的开始位置pivotXValue、pivotYValue等        fromDegrees、toDegrees属性值说明0.0表示收缩到没有 1.0表示正常无伸缩 值小于1.0表示收缩 值大于1.0表示放大。 

                              当角度为负数——表示逆时针旋转
                              当角度为正数——表示顺时针旋转
                              (负数from——to正数:顺时针旋转)
                              (负数from——to负数:逆时针旋转)
                              (正数from——to正数:顺时针旋转)
                              (正数from——to负数:逆时针旋转)

        pivotX、pivotY属性值说明:从0%-100%中取值,50%为物件的X或Y方向坐标上的中点位置


      3) ScaleAnimation实现代码:

1
2
3
4
5
        //初始化  
         Animation scaleAnimation =  new  ScaleAnimation( 0 .1f,  1 .0f, 0 .1f, 1 .0f);  
        //设置动画时间  
        scaleAnimation.setDuration( 500 );  
        this .startAnimation(scaleAnimation);

 

      ScaleAnimation类中

      第一个参数fromX ,第二个参数toX:分别是动画起始、结束时X坐标上的伸缩尺寸。

      第三个参数fromY ,第四个参数toY:分别是动画起始、结束时Y坐标上的伸缩尺寸。

      另外还可以设置伸缩模式pivotXType、pivotYType, 伸缩动画相对于x,y 坐标的开始位置pivotXValue、pivotYValue等。

     

     4)TranslateAnimation实现代码:

1
2
3
4
5
        //初始化  
        nimation translateAnimation =  new  TranslateAnimation( 0 .1f,  100 .0f, 0 .1f, 100 .0f);  
        //设置动画时间                
        translateAnimation.setDuration( 1000 );  
        this .startAnimation(translateAnimation);

   

     TranslateAnimation类 

     第一个参数fromXDelta ,第二个参数toXDelta:分别是动画起始、结束时X坐标。

    第三个参数fromYDelta ,第四个参数toYDelta:分别是动画起始、结束时Y坐标。


      5)AnimationSet实现代码:


1
2
3
4
5
6
7
8
9
10
11
12
13
             //初始化 Translate动画  
         translateAnimation =  new  TranslateAnimation( 0 .1f,  100 .0f, 0 .1f, 100 .0f);  
         //初始化 Alpha动画  
         alphaAnimation =  new  AlphaAnimation( 0 .1f,  1 .0f);  
       
         //动画集  
         AnimationSet set =  new  AnimationSet( true );  
          set.addAnimation(translateAnimation);  
         set.addAnimation(alphaAnimation);  
       
         //设置动画时间 (作用到每个动画)  
         set.setDuration( 1000 );  
         this .startAnimation(set);

   

      6)Interpolator

       用于修改一个动画过程中的速率,可以定义各种各样的非线性变化函数,比如加速、减速等。

       在Android中所有的插值器都是Interpolator 的子类,通过 android:interpolator 属性你可以引用不同的插值器。下面是几种插值

       你可以通过下面的方式使用它们:

1
2
          < set  android:interpolator = "@android:anim/accelerate_interpolator" >
             </ set >


       自定义插值器

       如果你对系统提供的插值器不满意,我们可以创建一个插值器资源修改插值器的属性,比如修改AnticipateInterpolator的加速速率,调整CycleInterpolator的循环次数等。为了完成这种需求,我们需要创建XML资源文件,然后将其放于/res/anim下,然后再动画元素中引用即可。我们先来看一下几种常见的插值器可调整的属性:

1
< span  style = "font-family:'宋体', SimSun;" >       <? xml  version = "1.0"  encoding = "utf-8" ?>< br >           < InterpolatorName  xmlns:android = "http://schemas.android.com/apk/res/android" <br>        android:attribute_name="value"< br >         />< br ></ span >

    

       android:factor 浮点值,加速速率,默认为1

       android:tension 浮点值,起始点后退的张力、拉力数,默认为2

       android:tension 同上 android:extraTension 浮点值,拉力的倍数,默认为1.5(2 * 1.5)

       android:cycles int,循环的个数,默认为1

       android:factor 浮点值,减速的速率,默认为1

       浮点值,超出终点后的张力、拉力,默认为2


       比如:res/anim/my_overshoot_interpolator.xml:

1
< span  style = "font-family:'宋体', SimSun;" >      <? xml  version = "1.0"  encoding = "utf-8" ?>< br >    < overshootInterpolator  xmlns:android = "http://schemas.android.com/apk/res/android" <br>    android:tension="7.0"/></ span >

    This animation XML will apply the interpolator:

1
< br >< span  style = "font-family:'宋体', SimSun;" >          < scale  xmlns:android = "http://schemas.android.com/apk/res/android" <br>        android:interpolator="@anim/my_overshoot_interpolator"< br >        android:fromXScale="1.0"< br >        android:toXScale="3.0"< br >        android:fromYScale="1.0"< br >        android:toYScale="3.0< br >        android:pivotX="50%"< br >        android:pivotY="50%"< br >        android:duration="700" /></ span >

    如果简单的修改插值器的属性值还不能够满足我们的需求,那么就自己来通过实现Interpolator接口来定义自己的插值器了因为上面所有的Interpolator都实现了Interpolator接口,这个接口定义了一个方法:float getInterpolation(float input);此方法由系统调用,input代表动画的时间,在0和1之间,也就是开始和结束之间。


    线性(匀速)插值器定义如下:

       

1
2
3
              public  float  getInterpolation( float  input) {  
             return  input;  
         }

    加速减速插值器定义如下:

1
2
3
             public float getInterpolation(float input) {  
         return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;  
         }



   2.PropertyAnimator动画

  Property Animation动画有两个步聚:
    a.计算属性值
    b.为目标对象的属性设置属性值,即应用和刷新动画

    1) 计算属性值

wKioL1f6bGTjC-pjAAGsVzG8ArY297.png-wh_50

     过程一:计算已完成动画分数 elapsed fraction
   为了执行一个动画,你需要创建一个ValueAnimator,并且指定目标对象属性的开始、结束值和持续时间。在调用start后的整个动画过程中, ValueAnimator会根据已经完成的动画时间计算得到一个0到1之间的分数,代表该动画的已完成动画百分比。0表示0%,1表示100%。

       过程二:计算插值(动画变化率)interpolated fraction
当ValueAnimator计算完已完成动画分数后,它会调用当前设置的TimeInterpolator,去计算得到一个interpolated(插值)分数,在计算过程中,已完成动画百分比会被加入到新的插值计算中。

       过程三:计算属性值
当插值分数计算完成后,ValueAnimator 会根据插值分数调用合适的 TypeEvaluator去计算运动中的属性值。
以上分析引入了两个概念:已完成动画分数(elapsed fraction)、插值分数( interpolated fraction 
)。

    核心类:

     wKiom1f6bVaAg82VAAAzkTjkLhc773.png-wh_50


    a. Evaluators

    Evaluators 告诉属性动画系统如何去计算一个属性值。它们通过Animator提供的动画的起始和结束值去计算一个动画的属性值。

    属性系统提供了以下几种Evaluators:

     1.IntEvaluator

     2.FloatEvaluator

     3.ArgbEvaluator

     这三个由系统提供,分别用于计算int,float,color型(十六进制)属性的计算器


    b.TypeEvaluator

    一个用于用户自定义计算器的接口,如果你的对象属性值类型,不是int,float,或者color类型,你必须实现这个接口,去定义自己的数据类型。TypeEvaluator接口只有一个方法,就是evaluate()方法,它允许你使用的animator返回一个当前动画点的属性值。

   c.ValueAnimator

   属性动画中的主要的时序引擎,如动画时间,开始、结束属性值,相应时间属性值计算方法等。包含了所有计算动画值的核心函数。也包含了每一个动画时间上的细节,信息,一个动画是否重复,是否监听更新事件等,并且还可以设置自定义的计算类型。

   使用ValueAnimator实现动画需要手动更新:


1
2
3
4
5
6
7
8
9
10
ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration( 1000 );
animation.addUpdateListener( new  AnimatorUpdateListener() {
@Override
public  void  onAnimationUpdate(ValueAnimator animation) {
Log.i( "update" , ((Float) animation.getAnimatedValue()).toString());
}
});
animation.setInterpolator( new  CycleInterpolator( 3 ));
animation.start();


   d.ObjectAnimator

   继承自ValueAnimator,允许你指定要进行动画的对象以及该对象的一个属性。该类会根据计算得到的新值自动更新属性。ObjectAnimator的自动更新功能,依赖于属性身上的setter和getter方法,所以为了让ObjectAnimator能够正确的更新属性值,你必须遵从以下规范:

1. 该对象的属性必须有get和set方法(方法的格式必须是驼峰式),方法格式为set(),因为ObjectAnimator会自动更新属性,它必须能够访问到属性的setter方法,比如属性名为foo,你就需要一个setFoo()方法,如果setter方法不存在,你有三种选择:

a.添加setter方法

b.使用包装类。通过该包装类通过一个有效的setter方法获取或者改变属性值的方法,然后应用于原始对象,比如NOA的AnimatorProxy。

c.使用ValueAnimator代替

(这3点的意思总结起来就是一定要有一个setter方法,让ObjectAnimator能够访问到)

 

如果你为ObjectAnimator的工厂方法的可变参数只传递了一个值,那么会被作为动画的结束值。


   e. AnimatorSet

   提供组合动画能力的类。并可设置组中动画的时序关系,如同时播放、有序播放或延迟播放。Elevator会告诉属性动画系统如何计算一个属性的值,它们会从Animator类中获取时序数据,比如开始和结束值,并依据这些数据计算动画的属性值。


   f.ViewPropertyAnimator

   可以方便的为某个View的多个属性添加并行的动画,只使用一个ViewPropertyAnimator对象就可以完成。它的行为更像一个ObjectAnimator,因为它修改的是对象的实际属性值。但它为一次性给多个属性添加动画提供了方便,而且使用ViewPropertyAnimator的代码更连贯更易读。

下面的代码段分别展示了使用多个ObjectAnimator对象、一个ObjectAnimator对象、 ViewPropertyAnimator同时为一个View的X和Y属性添加动画的示例:

多个ObjectAnimator结合AnimatorSet实现


1
2
3
4
5
ObjectAnimator animX = ObjectAnimator.ofFloat(myView,  "x" , 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView,  "y" , 100f);
AnimatorSet animSetXY =  new  AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();


一个ObjectAnimator结合多个PropertyValuesHolder实现

1
2
3
ropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat( "x" , 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat( "y" , 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();

ViewPropertyAnimator: 只需一行代码

1
myView.animate().x(50f).y(100f); //myView.animate()直接返回一个ViewPropertyAnimator对象

   g.PropertyValuesHolder

   顾名思义,该类持有属性,相关属性值的操作以及属性的setter,getter方法的创建,属性值以Keyframe来承载,最终由KeyframeSet统一处理。


   h.KeyFrame

   一个keyframe对象由一对 time / value的键值对组成,可以为动画定义某一特定时间的特定状态。每个keyframe可以拥有自己的插值器,用于控制前一帧和当前帧的时间间隔间内的动画。

Keyframe.ofFloat(0f,0f);

第一个参数为:要执行该帧动画的时间节点(elapsed time / duration)

第二个参数为属性值。

    因此如果你想指定某一特定时间的特定状态,那么简单的使用ObjectAnimator就满足不了你了,因为ObjectAnimator.ofInt(....)类似的工厂方法,无法指定特定的时间点的状态。

    每个KeyFrame其实也有个Interpolator。如果没有设置,默认是线性的。之前为Animator设置的Interpolator是整个动画的,而系统允许你为每一KeyFrame的单独定义Interpolator,系统这样做的目的是允许你在某一个keyFrame做特殊的处理,也就是整体上是按照你的插值函数来计算,但是,如果你希望某个或某些KeyFrame会有不同的动画表现,那么你可以为这个keyFrame设置Interpolator。因此,Keyframe的定制性更高,你如果想精确控制某一个时间点的动画值及其运动规律,你可以自己创建特定的Keyframe 。


Keyframe使用

为了实例化一个keyframe对象,你必须使用某一个工厂方法:ofInt(), ofFloat(), or ofObject() 去获取合适的keyframe类型,然后你调用ofKeyframe工厂方法去获取一个PropertyValuesHolder对象,一旦你拥有了该对象,你可以将PropertyValuesHolder作为参数获取一个Animator,如下:


1
2
3
4
5
6
Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe( "rotation" , kf0, kf1, kf2); //动画属性名,可变参数
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)
rotationAnim.setDuration( 5000 );

   i. KeyFrameSet


   根据Animator传入的值,为当前动画创建一个特定类型的KeyFrame集合。

通常通过ObjectAnimator.ofFloat(…)进行赋值时,这些值其实是通过一个KeyFrameSet来维护的

比如:

ObjectAnimator.ofFloat(target, "translateX", 50, 100, 200);

调用者传入的values 为 50,100,200,则numKeyframs = 3,那么创建出相应的Keyframe为:

Keyframe(0,50),Keyframe(1/2,100),Keyframe(1,200), 时间点 0,1/2,1 都是按比例划分的


1
2
3
4
5
6
7
8
9
10
11
12
13
public  static  KeyframeSet ofFloat( float ... values) {
int  numKeyframes = values.length;
FloatKeyframe keyframes[] =  new  FloatKeyframe[Math.max(numKeyframes, 2 )];
if  (numKeyframes ==  1 ) {
keyframes[ 0 ] = (FloatKeyframe) Keyframe.ofFloat(0f);
keyframes[ 1 ] = (FloatKeyframe) Keyframe.ofFloat(1f, values[ 0 ]);
else  {
keyframes[ 0 ] = (FloatKeyframe) Keyframe.ofFloat(0f, values[ 0 ]);
for  ( int  i =  1 ; i < numKeyframes; ++i) {
keyframes[i] = (FloatKeyframe) Keyframe.ofFloat(( float ) i / (numKeyframes -  1 ), values[i]); //这里是关键
}
}
return  new  FloatKeyframeSet(keyframes);


  2) 在XML中声明属性动画

   通过在XML中定义的动画,可以很方便的在多个Activities中重用而且更容易编辑,复用性强。为了区分新的属性动画,从3.1开始,你应res/animator/下存放属性动画的资源文件,使用animator文件夹是可选的,但是如果你想在Eclipse ADT插件中使用布局编辑工具(ADT 11.0.0+),就必须在res/animator文件夹下存放了,因为ADT只会查找res/animator文件夹下的属性动画资源文件。


属性动画支持的Tag有

ValueAnimator - <animator>

ObjectAnimator - <objectAnimator>

AnimatorSet - <set>


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
< 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 >


1
2
3
4
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
R.anim.property_animator);
set.setTarget(myObject);
set.start();


目录res/animator/filename.xm


编译后的资源为ValueAnimator, ObjectAnimator, or AnimatorSet


XML文件的根元素必须为<set>,<objectAnimator>, or <valueAnimator>之一。也可以在一个set中组织不同的动画,包含其它<set>元素,也就是说,可以嵌套。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
< set  
android:ordering=["together" | "sequentially"]>  
< objectAnimator  
android:propertyName = "string"  
android:duration = "int"  
android:valueFrom = "float | int | color"  
android:valueTo = "float | int | color"  
android:startOffset = "int"  
android:repeatCount = "int"  
android:repeatMode=["repeat" | "reverse"]  
android:valueType=["intType" | "floatType"]/>  
< animator  
android:duration = "int"  
android:valueFrom = "float | int | color"  
android:valueTo = "float | int | color"  
android:startOffset = "int"  
android:repeatCount = "int"  
android:repeatMode=["repeat" | "reverse"]  
android:valueType=["intType" | "floatType"]/>  
< set >  
...  
</ set >  
</ set >


  3.Andriod L的动画

     Material Design是Google推出的一个全新的设计语言,它的特点就是拟物扁平化。     

     在Android L中新增了如下几种动画:

      a. Touch feedback(触摸反馈)

      b. Reveal effect(揭露效果)

      c. Activity transitions(Activity转换效果)

      d. Curved motion(曲线运动)

      e. View state changes (视图状态改变)

      f. Animate Vector Drawables(可绘矢量动画)


 详细的内容如下:

    1. 触摸反馈:

    触摸反馈最具代表性的就是波纹动画,比如当点击按钮时会从点击的位置产生类似于波纹的扩散效果。

    1)波纹效果(Ripple):

     可以通过如下代码设置波纹的背景:android:background="?android:attr/selectableItemBackground"波纹有边界  android:background="?android:attr/selectableItemBackgroundBorderless"波纹超出边界


具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
< Button
         android:id = "@+id/btn_1"
         android:layout_width = "wrap_content"
         android:layout_height = "wrap_content"
         android:text = "@string/btn_1"
         android:padding = "10px"
         android:layout_below = "@id/touch_feedback_ripple_textview"
         />
     < Button
         android:id = "@+id/btn_2"
         android:layout_width = "wrap_content"
         android:layout_height = "wrap_content"
         android:text = "@string/btn_2"
         android:layout_below = "@id/btn_1"
         android:padding = "10px"
         android:background = "?android:attr/selectableItemBackground" />
     < Button
         android:id = "@+id/btn_3"
         android:layout_width = "wrap_content"
         android:layout_height = "wrap_content"
         android:text = "@string/btn_3"
         android:layout_below = "@id/btn_2"
         android:padding = "10px"
       android:background = "?android:attr/selectableItemBackgroundBorderless" />

效果如下:

wKioL1f6eEjQ29VnAAFGl6gbEN8743.gif

    2)设置颜色

     我们也可以通过设置xml属性来调节动画颜色,从而可以适应不同的主题:

      android:colorControlHighlight:设置波纹颜色 

     android:colorAccent:设置checkbox等控件的选中颜色


   2. Circular Reveal:

   使用方法:

   应用ViewAnimationUtils.createCircularReveal()方法可以去创建一个RevealAnimator动画 。

   ViewAnimationUtils.createCircularReveal源码如下:

1
2
3
  public  static  Animator createCircularReveal(View view,nt centerX,   int  centerY,  float  startRadius,  float  endRadius) {  
   return  new  RevealAnimator(view, centerX, centerY, startRadius, endRadius); 
   }

源码非常简单,就是通过createCircularReveal方法根据5个参数来创建一个RevealAnimator动画对象。


这五个参数分别是:

view 操作的视图

  centerX 动画开始的中心点X

  centerY 动画开始的中心点Y

  startRadius 动画开始半径

  startRadius 动画结束半径


实例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
final  View oval =  this .findViewById(R.id.oval);  
     oval.setOnClickListener( new  View.OnClickListener() {  
         @Override  
         public  void  onClick(View v) {  
             Animator animator = ViewAnimationUtils.createCircularReveal(  
                     oval,oval.getWidth()/ 2 ,oval.getHeight()/ 2 ,oval.getWidth(), 0 );  
             animator.setInterpolator( new  AccelerateDecelerateInterpolator());  
             animator.setDuration( 2000 );  
             animator.start();  
         }  
     });  
       
final  View rect =  this .findViewById(R.id.rect);  
       
rect.setOnClickListener( new  View.OnClickListener() {  
         @Override  
         public  void  onClick(View v) {  
             Animator animator = ViewAnimationUtils.createCircularReveal(  
                     rect, 0 , 0 , 0 ,( float ) Math.hypot(rect.getWidth(), rect.getHeight()));  
             animator.setInterpolator( new  AccelerateInterpolator());  
             animator.setDuration( 2000 );  
             animator.start();  
         }  
});

显示效果:

 wKiom1f6eebz3kCDAAEk_72R9Xk661.gif



 3. Activity Transition


   1) 什么是Transition?

   安卓5.0中Activity和Fragment 变换是建立在名叫Transitions的安卓新特性之上的。这个诞生于4.4的transition框架为在不同的UI状态之间产生动画效果提供了非常方便的API。该框架主要基于两个概念:场景(scenes)和变换(transitions)。场景(scenes)定义了当前的UI状态,变换(transitions)则定义了在不同场景之间动画变化的过程。虽然transition翻译为变换似乎很确切,但是总觉得还是没有直接使用transition直观,为了更好的理解下面个别地方直接用transition代表变换。


   当一个场景改变的时候,transition主要负责:

  (1)捕捉每个View在开始场景和结束场景时的状态。

  (2)根据两个场景(开始和结束)之间的区别创建一个Animator。


   2) Android 5.0(API 级别 21)支持这些进入与退出转换:

     (1)分解 - 从场景中心移入或移出视图。

     (2)滑动 - 从场景边缘移入或移出视图。

     (3)淡入淡出 - 通过调整透明度在场景中增添或移除视图。


   3)Android 5.0(API 级别 21)也支持这些共享元素转换:

     (1)changeBounds - 为目标视图的布局边界的变化添加动画。

     (2) changeClipBounds - 为目标视图的裁剪边界的变化添加动画。

     (3)changeTransform - 为目标视图的缩放与旋转变化添加动画。

     (4)changeImageTransform - 为目标图像的大小与缩放变化添加动画。


   4) 实现方式:

     (1). xml 实现方式:

      res/transition/activity_fade.xml

1
2
3
4
5
6
7
<? xml  version = "1.0"  encoding = "utf-8" ?>
< fade  xmlns:android = "http://schemas.android.com/apk/res/"
android:duration = "1000" />
res/transition/activity_slide.xml
<? xml  version = "1.0"  encoding = "utf-8" ?>
< slide  xmlns:android = "http://schemas.android.com/apk/res/"
android:duration = "1000" />

    MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
     @Override
     protected  void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.activity_transition);
         setupWindowAnimations();
     }
  
     private  void  setupWindowAnimations() {
Slide slide = TransitionInflater.from( this ).inflateTransition(R.transition.activity_slide);
getWindow().setExitTransition(slide);
}
@Override
     protected  void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.activity_transition);
         setupWindowAnimations();
}
private  void  setupWindowAnimations() {
         Fade fade = TransitionInflater.from( this ).inflateTransition(R.transition.activity_fade);
         getWindow().setEnterTransition(fade);
     }

 

    (2)代码实现方式:

     MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
  @Override
     protected  void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.activity_transition);
         setupWindowAnimations();
     }
     private  void  setupWindowAnimations() {
         Slide slide =  new  Slide();
         slide.setDuration( 1000 );
         getWindow().setExitTransition(slide);
     }

     TransitionActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
     @Override
     protected  void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.activity_transition);
         setupWindowAnimations();
     }
  
     private  void  setupWindowAnimations() {
         Fade fade =  new  Fade();
         fade.setDuration( 1000 );
         getWindow().setEnterTransition(fade);
     }


实例代码:


   (1). Styles文件 :

1
2
3
4
5
6
7
8
9
10
11
12
   < resources >
     < style  name = "AppTheme"  parent = "Theme.AppCompat.Light.DarkActionBar" >
         < item  name = "colorPrimary" >@color/colorPrimary</ item >
         < item  name = "colorPrimaryDark" >@color/colorPrimaryDark</ item >
         < item  name = "colorAccent" >@color/colorAccent</ item <!--设置选中的颜色-->
         <!-- 允许使用transitions -->
         < item  name = "android:windowContentTransitions" >true</ item >
         <!--是否覆盖执行,其实可以理解成是否同步执行还是顺序执行-->
         < item  name = "android:windowAllowEnterTransitionOverlap" >false</ item >
         < item  name = "android:windowAllowReturnTransitionOverlap" >false</ item >
     </ style >
</ resources >



   (2). MainActivity部分代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
  @Override
     public  void  onClick(View v) {
         ArrayList<Pair<View,String>> arrayList =  new  ArrayList<Pair<View,String>>();
         switch  (v.getId()) {
             case  R.id.explode_btn:
                 setExplodeTransition();
                 flag = AnimConstant.EXPLODE_FLAG;
                 break ;
             case  R.id.slide_btn:
                 setSlideTransition();
                 flag = AnimConstant.SLIDE_FLAG;
                 break ;
             case  R.id.pade_in_out_btn:
                 setFadeTransition();
                 flag = AnimConstant.PADE_IN_OUT_FLAG;
                 break ;
             case  R.id.shared_element_btn:
                 arrayList.add( new  Pair<View, String>(shareElementBtn,  "shared_name_btn" ));
                 flag = AnimConstant.SHARED_ELEMENTS_FLAG;
                 break ;
         }
         startActivity(arrayList);
     }
     private  void  setFadeTransition() {
         Fade fadeTransition =  new  Fade();
         fadeTransition.setDuration( 1000 );
         getWindow().setReenterTransition(fadeTransition);
         getWindow().setExitTransition(fadeTransition);
     }
  
     private  void  startActivity(ArrayList<Pair<View, String>> arrayList) {
         Intent intent =  new  Intent();
         intent.setClass( this  ,SecondActivity. class );
         intent.putExtra( "transition_flag" ,flag);
         ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation( this , arrayList.toArray( new  Pair[arrayList.size()]));
         startActivity(intent, options.toBundle());
     }
    private  void  setExplodeTransition() {
         Explode explode =  new  Explode();
         explode.setDuration( 2000 );
         getWindow().setReenterTransition(explode);
         getWindow().setExitTransition(explode);
     }
     private  void  setSlideTransition() {
         Slide slideTransition =  new  Slide();
         slideTransition.setSlideEdge(Gravity.LEFT);
         slideTransition.setDuration( 1000 );
         getWindow().setReenterTransition(slideTransition);
         getWindow().setExitTransition(slideTransition);
}

  (3) SecondActivity类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
   private  Button returnBtn =  null ;
  
     @Override
     protected  void  onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.activity_second);
         Intent intent = getIntent();
         int  flag = intent.getIntExtra( "transition_flag"  ,- 1 );
         if  (flag != AnimConstant.SHARED_ELEMENTS_FLAG) {
             setupWindowAnimations();
         }
         returnBtn = (Button)  this .findViewById(R.id.return_btn);
         returnBtn.setOnClickListener( new  View.OnClickListener() {
             @Override
             public  void  onClick(View v) {
                 finishAfterTransition();
             }
         });
     }
  
     private  void  setupWindowAnimations() {
         Explode explode =  new  Explode();
         explode.setDuration( 2000 );
         getWindow().setEnterTransition(explode);
     }

显示效果:

wKiom1f6fUmQRGxEAAuLmgoJFJQ552.gif

   4.Curved motion

              Material design中的动画利用曲线实现时间内插与空间移动模式。 在 Android 5.0API 级别 21)及更高版本,您可为动画定义定制时间曲线以及曲线运动模式。PathInterpolator 类别是一个基于贝塞尔曲线或 Path 对象的全新插入器。 此插入器在一个 1x1 的正方形内指定一个运动曲线,定位点位于 (0,0) 以及 (1,1),而控制点则使用构造函数参数指定。 

有两种定义PathInterpolator的方法:

 第一种XML方式:

1
2
3
4
5
< pathInterpolator  xmlns:android = "http://schemas.android.com/apk/res/android"
     android:controlX1 = "0.4"
     android:controlY1 = "0"
     android:controlX2 = "1"
     android:controlY2 = "1" />


系统将为材料设计规范中的三种基本曲线提供 XML 资源:

@interpolator/fast_out_linear_in.xml

@interpolator/fast_out_slow_in.xml

@interpolator/linear_out_slow_in.xml


第二种代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public  class  SCPahtInterpolator  extends  PathInterpolator {
     public  static  final  float  DEFALUT_CONTROL_1_X =  0 .5f;
     public  static  final  float  DEFALUT_CONTROL_1_Y = 0f;
     public  static  final  float  DEFALUT_CONTROL_2_X = 0f;
     public  static  final  float  DEFALUT_CONTROL_2_Y = 1f;
     public  SCPahtInterpolator() {
         super (DEFALUT_CONTROL_1_X, DEFALUT_CONTROL_1_Y, DEFALUT_CONTROL_2_X, DEFALUT_CONTROL_2_Y);
     }
     public  SCPahtInterpolator(Path path) {
         super (path);
     }
     public  SCPahtInterpolator( float  controlX,  float  controlY) {
         super (controlX, controlY);
     }
     public  SCPahtInterpolator( float  controlX1,  float  controlY1,  float  controlX2,  float  controlY2) {
         super (controlX1, controlY1, controlX2, controlY2);
     }
     public  SCPahtInterpolator(Context context, AttributeSet attrs) {
         super (context, attrs);
     }
}

可用Animator.setInterpolator()设置PathInterpolator

ObjectAnimator 类别拥有新的构造函数,可让您一次使用两个或更多属性在路径上为坐标添加动画。 例如,下列动画使用 Path 对象为视图的 X 和 Y 属性添加动画:

1
2
3
4
ObjectAnimator mAnimator;
mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path);
...
mAnimator.start();


   5.视图状态改变

   StateListAnimator 类别让您能够定义视图状态改变时运行的动画。 下列示例显示如何将 StateListAnimator 定义为一个 XML 资源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- animate the translationZ property of a view when pressed -->
< selector  xmlns:android = "http://schemas.android.com/apk/res/android" >
   < item  android:state_pressed = "true" >
     < set >
       < objectAnimator  android:propertyName = "translationZ"
         android:duration = "@android:integer/config_shortAnimTime"
         android:valueTo = "2dp"
         android:valueType = "floatType" />
         <!-- you could have other objectAnimator elements
              here for "x" and "y", or other properties -->
     </ set >
   </ item >
   < item  android:state_enabled = "true"
     android:state_pressed = "false"
     android:state_focused = "true" >
     < set >
       < objectAnimator  android:propertyName = "translationZ"
         android:duration = "100"
         android:valueTo = "0"
         android:valueType = "floatType" />
     </ set >
   </ item >
</ selector >


如果要将定制视图状态动画附加至一个视图,请依照此示例使用 XML 资源文件中的 selector 元素定义一个动画,并使用 android:stateListAnimator属性将此动画分配给您的视图。 如果要将一个状态列表动画分配给您的代码内的一个视图,请使用 AnimationInflater.loadStateListAnimator() 方法,并以 View.setStateListAnimator() 方法将动画分配给您的视图。

当您的主题扩展材料主题时,在默认情况下按钮将拥有一个 Z 动画。如果要避免您的按钮出现这类行为,请将 android:stateListAnimator 属性设置为@null。

AnimatedStateListDrawable 类别让您能够创建图片,显示相关视图之间的状态变化。 Android 5.0 中的某些系统小组件在默认情况下使用这些动画。 下列示例显示如何将 AnimatedStateListDrawable 定义为一个 XML 资源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- res/drawable/myanimstatedrawable.xml -->
< animated-selector
     xmlns:android = "http://schemas.android.com/apk/res/android" >
  
     <!-- provide a different drawable for each state-->
     < item  android:id = "@+id/pressed"  android:drawable = "@drawable/drawableP"
         android:state_pressed = "true" />
     < item  android:id = "@+id/focused"  android:drawable = "@drawable/drawableF"
         android:state_focused = "true" />
     < item  android:id = "@id/default"
         android:drawable = "@drawable/drawableD" />
  
     <!-- specify a transition -->
     < transition  android:fromId = "@+id/default"  android:toId = "@+id/pressed" >
         < animation-list >
             < item  android:duration = "15"  android:drawable = "@drawable/dt1" />
             < item  android:duration = "15"  android:drawable = "@drawable/dt2" />
             ...
         </ animation-list >
     </ transition >
     ...
</ animated-selector >


 

   6.为矢量图片添加动画

   矢量图片可在不丢失定义的情况下缩放。 AnimatedVectorDrawable 类别可让您为矢量图片的属性添加动画。

您通常可以在 3 个 XML 文件中定义添加动画的矢量图片:

在 res/drawable/ 中拥有 <vector> 元素的矢量图片

在 res/drawable/ 中拥有 <animated-vector> 元素且已添加动画的矢量图片

在 res/anim/ 中拥有 <objectAnimator> 元素的一个或多个对象动画

添加动画的矢量图片可为 <group> 以及 <path> 元素的属性添加动画。<group> 元素定义路径集或子组,而 <path> 元素则定义将绘制的路径。

当您定义一个您想要添加动画的矢量图片时,请使用 android:name 属性给这些群组和路径指定一个唯一名称,以便让您能够从您的动画定义中引用这些群组或路径。 例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- res/drawable/vectordrawable.xml -->
< vector  xmlns:android = "http://schemas.android.com/apk/res/android"
     android:height = "64dp"
     android:width = "64dp"
     android:viewportHeight = "600"
     android:viewportWidth = "600" >
     < group
         android:name = "rotationGroup"
         android:pivotX = "300.0"
         android:pivotY = "300.0"
         android:rotation = "45.0"  >
         < path
             android:name = "v"
             android:fillColor = "#000000"
             android:pathData = "M300,70 l 0,-70 70,70 0,0 -70,70z"  />
     </ group >
</ vector >

已添加动画的矢量图片定义按名称引用矢量图片内的群组和路径:

1
2
3
4
5
6
7
8
9
10
<!-- res/drawable/animvectordrawable.xml -->
< animated-vector  xmlns:android = "http://schemas.android.com/apk/res/android"
   android:drawable = "@drawable/vectordrawable"  >
     < target
         android:name = "rotationGroup"
         android:animation = "@anim/rotation"  />
     < target
         android:name = "v"
         android:animation = "@anim/path_morph"  />
</ animated-vector >


动画定义代表着 ObjectAnimator 或 AnimatorSet 对象。此示例中的第一个动画将目标群组旋转 360 度:

1
2
3
4
5
6
<!-- res/anim/rotation.xml -->
< objectAnimator
     android:duration = "6000"
     android:propertyName = "rotation"
     android:valueFrom = "0"
     android:valueTo = "360"  />


此示例中的第二个动画对矢量图片的路径进行变形。 两个路径均需可兼容变形操作:两个路径均需拥有相同数量的指令,而且每个指令均需拥有相同数量的参数。


1
2
3
4
5
6
7
8
9
<!-- res/anim/path_morph.xml -->
< set  xmlns:android = "http://schemas.android.com/apk/res/android" >
     < objectAnimator
         android:duration = "3000"
         android:propertyName = "pathData"
         android:valueFrom = "M300,70 l 0,-70 70,70 0,0   -70,70z"
         android:valueTo = "M300,70 l 0,-70 70,0  0,140 -70,0 z"
         android:valueType = "pathType"  />
</ set >



引用的文章:

   http://www.open-open.com/lib/view/open1416663769680.html

   http://blog.youkuaiyun.com/feng88724/article/details/6318430

   http://www.lightskystreet.com/2015/05/23/anim_basic_knowledge/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值