android 动画

1,353 阅读21分钟

补间动画

原理:
  通过确定开始和结束时的视图样式, 中间动画的变化过程由系统来补全。

作用对象:
  作用于View对象,不可作用于View的颜色,背景等属性

分类:

  • 平移(Translate)
  • 缩放(Scale)
  • 旋转(Rotate)
  • 透明度(Alpha)

    对应的具体实现类
名称 原理 实现类
平移动画(Translate) 移动视图的位置 TranslateAnimation
缩放动画(Scale) 放大或者缩小视图大小 ScaleAnimation
旋转动画(Rotate) 旋转视图 RotateAnimation
透明动画(Alpha) 改变视图的透明度 AlphaAnimation

TIPS:
  补间动画只会改变View的视觉效果图,在ScalAnimation和TranslateAnimation中,不会改变View在屏幕上的位置,所以就会导致在执行TranslateAniamtion时,点击平移的View不会触发click监听,只有点击它原来的位置时才会触发click监听。

***4种动画(包括set组合动画)共有的属性:***

Animation属性 解释
android:duration 动画执行的时间
android:fillAfter 如果为true,那么动画执行完就会定格在执行完的那个画面,也就是动画的最后一帧,不会恢复到原位。优先于fillBefore值,默认为false
android:fillBefore 动画播放完后,视图是否会停留在动画开始的状态。只有当android:fillEnable为true时,才有效
android:fillEnabled 是否考虑android:fillBefore的值。只要为true时,android:fillBefore的值才会被考虑。
android:interpolator 设置插值器,控制动画不同时间段的速度,默认是加速减速插值器。
android:repeatCount 动画重复的次数,所以总共会运行的动画次数是这个重复次数+1;为infinite时无限重复
android:repeatMode 动画重复的方式,有两个值,reverse 和 restart。reverse表示动画会正反轮流执行;restart
android:startOffset 动画延迟执行的时间,单位是毫秒

插值器

插值器 xml中的值 效果
AccelerateDecelerateInterpolator @android:anim/accelerate_decelerate_interpolator 加速减速插值器 动画先加速再减速
AccelerateInterpolator @android:anim/accelerate_interpolator 加速插值器 动画速度越来越快
DecelerateInterpolator @android:anim/decelerate_interpolator 减速插值器 动画速度越来越慢
BounceInterpolator @android:anim/bounce_interpolator 回弹插值器 动画结束会回弹几下
CycleInterpolator @android:anim/cycle_interpolator 圆插值器,动画会重复几次,动画的速度沿着正弦曲线变化
LinearInterpolator @android:anim/linear_interpolator 线性插值器 动画速度保持匀速
AnticipateOvershootInterpolator @android:anim/anticipate_overshoot_interpolator 预期预期超调插值器。先往前甩一定的值,然后开始动画,结束时往后甩一定的值,结束动画。
AnticipateInterpolator @android:anim/anticipate_interpolator 预期插值器,动画开始时会往前甩一下
OvershootInterpolator @android:anim/overshoot_interpolator 超调插值器 动画结束时往后甩一下

具体使用
  在xml中或者java代码中。

     Translate:
       xml初始化

  <!--
 以下参数是4种动画效果的公共属性,即都有的属性
    android:duration="3000" // 动画持续时间(ms),必须设置,动画才有效果
    android:startOffset ="1000" // 动画延迟开始时间(ms)
    android:fillBefore = “true” // 动画播放完后,视图是否会停留在动画开始的状态,默认为true
    android:fillAfter = “false” // 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false
    android:fillEnabled= “true” // 是否应用fillBefore值,对fillAfter值无影响,默认为true
    android:repeatMode= “restart” // 选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart|
    android:repeatCount = “0” // 重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复

     以下参数是平移动画特有的属性
    android:fromXDelta="0" // 视图在水平方向x 移动的起始值
    android:toXDelta="100%" // 视图在水平方向x 移动的结束值

    android:fromYDelta="0" // 视图在竖直方向y 移动的起始值
    android:toYDelta="500" // 视图在竖直方向y 移动的结束值
    -->
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="3000"
        android:startOffset ="10"
        android:fillBefore = "true"
        android:fillAfter = "false"
        android:fillEnabled= "false"
        android:repeatMode= "restart"
        android:repeatCount = "0"
        android:interpolator = "@android:anim/bounce_interpolator"
    
        android:fromXDelta="0"
        android:toXDelta="100%"
        android:fromYDelta="0"
        android:toYDelta="100%"/>
    
        //在class中使用:
        translateAnimation = AnimationUtils.loadAnimation(this,R.anim.anim_translate)
        btn.startAnimation(translateAnimation)

       java代码初始化:

~~~
 fun initTraslateForCode() : Animation{
 //绝对坐标
       // translateAnimation = TranslateAnimation(0F,100F,0F,100F)
 //绝对坐标
      //  translateAnimation = TranslateAnimation(Animation.ABSOLUTE,0F,Animation.ABSOLUTE,150F,Animation.ABSOLUTE,0F,Animation.ABSOLUTE,150F)
  //相对于自己的百分比坐标
        translateAnimation = TranslateAnimation(Animation.RELATIVE_TO_SELF,0F,Animation.RELATIVE_TO_SELF,100F,Animation.RELATIVE_TO_SELF,0F,Animation.RELATIVE_TO_SELF,100F)
 //相对于ParentView的百分比坐标
       // translateAnimation = TranslateAnimation(Animation.RELATIVE_TO_PARENT,0F,Animation.RELATIVE_TO_PARENT,100F,Animation.RELATIVE_TO_PARENT,0F,Animation.RELATIVE_TO_PARENT,100F)
        translateAnimation.duration = 3000

    return translateAnimation
}
~~~

TranslateAnimation独有属性

TranslateAnimation独有属性 含义
android:fromXDelta 动画开始时View左上角的X坐标,也有三种写法:
数值:50;百分数:50%;百分数p:50%p。
如果是数值,表示以View的左上角为(0,0),然后加上写的数值,以这个点作为开始点。
如果为百分数,如50%,表示总左上角(0,0)加上自身高度的50%,
作为开始点。
如果是百分数p,如50%p,表示总左上角(0,0)加上父控件高度的50%,作为开始点。
android:fromYDelta 动画开始时View左上角的Y坐标,也有三种写法
android:toXDelta 动画结束时View左上角的X坐标,也有三种写法
android:toYDelta 动画结束时View左上角的Y坐标,也有三种写法

Scale:
  ScaleAnimation独有属性:

ScaleAnimation独有属性 含义
android:pivotX float,缩放起点,或缩放原点的X轴坐标。
缩放围绕这个点运行。 这个坐标默认是View的左上角,(0,0)
在XML中的值有三种写法.
android:pivotY float,同上 Y轴坐标. 在XML中的值有三种写法
android:fromXScale float 动画开始时,X轴上缩放的比例。1表示本身大小。
android:fromYScale float 动画开始时,Y轴上缩放的比例。1表示本身大小。
android:toXScale float Y动画结束时,X轴上缩放的比例。1表示本身大小。
android:toYScale float Y动画结束时,Y轴上缩放的比例。1表示本身大小。

Rotate   Rotate独有属性:

RotateAnimation独有属性 含义
android:pivotX 旋转动画的中心的X坐标,旋转围绕这个点进行,也有三种写法,
android:pivotY 旋转动画的中心的Y坐标,旋转围绕这个点进行,也有三种写法
android:fromDegrees 动画开始时的旋转角度。角度顺时针转增加,逆时针转减少。
所以根据开始角度和结束角度来判断是顺时针还是逆时针。360度为一圈。
android:toDegrees 动画结束时的旋转角度。

Alpha   Alpha独有属性:

AlphaAnimation的独有属性 含义
android:fromAlpha 动画开始时的透明度 从0.0-1.0 0.0表示完全透明,1.0表示完全不透明
android:toAlpha 动画结束时的透明度

set组合动画

//anim_set.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
   android:duration="3000">
   <rotate
       android:pivotX="50%"
       android:pivotY="50%"
       android:fromDegrees="360"
       android:toDegrees="-90"
       />
   <alpha
       android:fromAlpha="1"
       android:toAlpha="0.2"/>
</set>
//java
Animation translateAnimation = AnimationUtils.loadAnimation(this, R.anim.set);
// 步骤2:创建 动画对象 并传入设置的动画效果xml文件
mButton.startAnimation(translateAnimation);

java代码设置:

 // 组合动画设置
AnimationSet setAnimation = new AnimationSet(true);
// 步骤1:创建组合动画对象(设置为true)
// 步骤2:设置组合动画的属性
// 特别说明以下情况
// 因为在下面的旋转动画设置了无限循环(RepeatCount = INFINITE)
// 所以动画不会结束,而是无限循环
// 所以组合动画的下面两行设置是无效的
setAnimation.setRepeatMode(Animation.RESTART);
setAnimation.setRepeatCount(1);// 设置了循环一次,但无效
// 步骤3:逐个创建子动画(方式同单个动画创建方式)
// 子动画1:旋转动画
Animation rotate = new RotateAnimation(0,360,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
rotate.setDuration(1000);
rotate.setRepeatMode(Animation.RESTART);
rotate.setRepeatCount(Animation.INFINITE);

// 子动画2:平移动画
Animation translate = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_PARENT,-0.5f,
        TranslateAnimation.RELATIVE_TO_PARENT,0.5f,
        TranslateAnimation.RELATIVE_TO_SELF,0
        ,TranslateAnimation.RELATIVE_TO_SELF,0);
translate.setDuration(10000);

// 子动画3:透明度动画
Animation alpha = new AlphaAnimation(1,0);
alpha.setDuration(3000);
alpha.setStartOffset(7000);

// 子动画4:缩放动画
Animation scale1 = new ScaleAnimation(1,0.5f,1,0.5f,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
scale1.setDuration(1000);
scale1.setStartOffset(4000);

// 步骤4:将创建的子动画添加到组合动画里
setAnimation.addAnimation(alpha);
setAnimation.addAnimation(rotate);
setAnimation.addAnimation(translate);
setAnimation.addAnimation(scale1);

动画的监听   补间动画只需设置开始视图和结束视图,中间的动画过程由系统完成,因此智能监听器开始和结束状态。

animation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                Log.i(TAG, "动画开始时做操作: ");
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                Log.i(TAG, "动画重复时做操作: ");
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                Log.i(TAG, "动画结束时做操作: ");
            }
        });

补充:ListView可以设置出场动画

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFFF"
    android:orientation="vertical" >
    <ListView
        android:id="@+id/listView1"
        android:layoutAnimation="@anim/anim_layout"
        // 指定layoutAnimation属性用以指定子元素的入场动画
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

逐帧动画

作用对象 视图控件(View)

1.如Android的TextView、Button等等
2.不可作用于View组件的属性,如:颜色、背景、长度等等

原理

  • 将动画拆分为 帧 的形式,且定义每一帧 = 每一张图片
  • 逐帧动画的本质:按序播放一组预先定义好的图片

具体使用 xml:

//knight_attack.xml
<?xml version="1.0" encoding="utf-8"?>
<animation-list
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:oneshot="true" // 设置是否只播放一次,默认为false>

// item = 动画图片资源;duration = 设置一帧持续时间(ms)
   <item android:drawable="@drawable/a0" android:duration="100"/>
   <item android:drawable="@drawable/a1" android:duration="100"/>
   <item android:drawable="@drawable/a2" android:duration="100"/>
   <item android:drawable="@drawable/a3" android:duration="100"/>
   <item android:drawable="@drawable/a4" android:duration="100"/>
   <item android:drawable="@drawable/a5" android:duration="100"/>
   <item android:drawable="@drawable/a6" android:duration="100"/>
   <item android:drawable="@drawable/a7" android:duration="100"/>
   <item android:drawable="@drawable/a8" android:duration="100"/>
   <item android:drawable="@drawable/a9" android:duration="100"/>
   <item android:drawable="@drawable/a10" android:duration="100"/>
   <item android:drawable="@drawable/a11" android:duration="100"/>
   <item android:drawable="@drawable/a12" android:duration="100"/>
   <item android:drawable="@drawable/a13" android:duration="100"/>
   <item android:drawable="@drawable/a14" android:duration="100"/>
   <item android:drawable="@drawable/a15" android:duration="100"/>
   <item android:drawable="@drawable/a16" android:duration="100"/>
   <item android:drawable="@drawable/a17" android:duration="100"/>
   <item android:drawable="@drawable/a18" android:duration="100"/>
   <item android:drawable="@drawable/a19" android:duration="100"/>
   <item android:drawable="@drawable/a20" android:duration="100"/>
   <item android:drawable="@drawable/a21" android:duration="100"/>
   <item android:drawable="@drawable/a22" android:duration="100"/>
   <item android:drawable="@drawable/a23" android:duration="100"/>
   <item android:drawable="@drawable/a24" android:duration="100"/>
   <item android:drawable="@drawable/a25" android:duration="100"/>
</animation-list>

//java 代码:
iv.setImageResource(R.drawable.knight_attack);
               // 1. 设置动画
               animationDrawable = (AnimationDrawable) iv.getDrawable();
               // 2. 获取动画对象
               animationDrawable.start();
   

在Java代码中实现:

 animationDrawable = new AnimationDrawable();
 for (int i = 0; i <= 25; i++) {
            int id = getResources().getIdentifier("a" + i, "drawable", getPackageName());
            Drawable drawable = getResources().getDrawable(id);
            animationDrawable.addFrame(drawable, 100);
 }
 animationDrawable.setOneShot(true);
 iv.setImageDrawable(animationDrawable);
 // 获取资源对象
 animationDrawable.stop();
 // 特别注意:在动画start()之前要先stop(),不然在第一次动画之后会停在最后一帧,这样动画就只会触发一次
 animationDrawable.start();
 // 启动动画

作者:Carson_Ho
链接:https://www.jianshu.com/p/225fe1feba60

注意
  尽量避免使用尺寸较大的图片,否则会引起oom

属性动画

补间动画的局限性:
  1.作用对象有局限性,只能作用在View上,无法对view的属性进行动哈操作;
  2.没有改变View的属性,只是改变视觉效果;
  3.效果单一,智能实现平移,选择,缩放,透明度4中或者这4种组合的动画

属性动画的原理
在一定时间间隔内,通过不断对值进行改变,并不断将该值赋给对象的属性,从而实现该对象在该属性上的动画效果

ValueAnimation

  • ValueAnimator.ofInt(int values)
      将初始值 以整型数值的形式 过渡到结束值,即使整型估值器 - IntEvalutor
 private void initValueAnimator() {
        // ofInt()作用有两个
        // 1. 创建动画实例
        //2. 将传入的多个Int参数进行平滑过渡:此处传入0和1,表示将值从0平滑过渡到1
        // 如果传入了3个Int参数 a,b,c ,则是先从a平滑过渡到b,再从b平滑过渡到C,以此类推
        // ValueAnimator.ofInt()内置了整型估值器,直接采用默认的.不需要设置,即默认设置了如何从初始值 过渡到 结束值
        final ValueAnimator valueAnimator = ValueAnimator.ofInt(0,3);

        // 步骤2:设置动画的播放各种属性
        valueAnimator.setDuration(500);

        // 设置动画延迟播放时间
        valueAnimator.setStartDelay(500);

        // 设置动画重复播放次数 = 重放次数+1
        // 动画播放次数 = infinite时,动画无限重复
        valueAnimator.setRepeatCount(0);

        // 设置重复播放动画模式
        // ValueAnimator.RESTART(默认):正序重放
        // ValueAnimator.REVERSE:倒序回放
        valueAnimator.setRepeatMode(ValueAnimator.RESTART);

        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                int currentValue = (int) animation.getAnimatedValue();
                Log.i("ValueAnimator:" , currentValue +"");
                //todo 将值赋值给View的某个绘制属性,并重新绘制View。
            }
        });
        valueAnimator.start();
    }

结果为:

05-10 22:06:44.078 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.094 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.115 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.133 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.151 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.169 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.187 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.204 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.224 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.241 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 0
05-10 22:06:44.258 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 1
05-10 22:06:44.276 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 1
05-10 22:06:44.294 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 1
05-10 22:06:44.312 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 1
05-10 22:06:44.331 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 1
05-10 22:06:44.347 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 1
05-10 22:06:44.366 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 1
05-10 22:06:44.386 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.405 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.423 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.440 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.459 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.476 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.493 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.511 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.530 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.548 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 2
05-10 22:06:44.567 4618-4618/com.aoyj.animaiton.valueanimationmaster I/ValueAnimator:: 3

可以将动画写在在xml中,但是这样子value的初始值和结束值都时事先固定的。

//set_anim.xml
<animator xmlns:android="http://schemas.android.com/apk/res/android"  
    android:valueFrom="0"   // 初始值
    android:valueTo="100"  // 结束值
    android:valueType="intType" // 变化值类型 :floatType & intType

    android:duration="3000" // 动画持续时间(ms),必须设置,动画才有效果
    android:startOffset ="1000" // 动画延迟开始时间(ms)
    android:fillBefore = “true” // 动画播放完后,视图是否会停留在动画开始的状态,默认为true
    android:fillAfter = “false” // 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false
    android:fillEnabled= “true” // 是否应用fillBefore值,对fillAfter值无影响,默认为true
    android:repeatMode= “restart” // 选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart|
    android:repeatCount = “0” // 重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复
    android:interpolator = @[package:]anim/interpolator_resource // 插值器,即影响动画的播放速度,下面会详细讲
/>

//在java代码中使用
ValueAnimator valueAnimator = ValueAnimatorInflater.loadAnimator(context,R.anim.set_anim);
valueAnimator.start();

作者:Carson_Ho
链接:https://www.jianshu.com/p/2412d00a0ce4
來源:简书

***ValueAnimator.ofFloat()***
  与ValueAnimator.ofiInt()类似

ValueAnimator.ofObject()
  ValueAnimator.ofInt()与ValueAnimator.ofFloat()都有内置的估值器,ValueAnimator.ofFloat()的估值器FloatEvaluetor实现为:

public class FloatEvaluator implements TypeEvaluator {  
// FloatEvaluator实现了TypeEvaluator接口

// 重写evaluate()
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
// 参数说明
// fraction:表示动画完成度(根据它来计算当前动画的值)
// startValue、endValue:动画的初始值和结束值
        float startFloat = ((Number) startValue).floatValue();  
        
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);  
        // 初始值 过渡 到结束值 的算法是:
        // 1. 用结束值减去初始值,算出它们之间的差值
        // 2. 用上述差值乘以fraction系数
        // 3. 再加上初始值,就得到当前动画的值
    }  
}

对于ValueAnimator.ofObject(),我自定义Evaluetor

public class ObjectEvaluetor implements TypeEvaluetor{
    @Override
    public Object evaluetor(float fraction,Object startValue,Object endValue){
        //fraction 为执行动画的完成度
        //startValue endValue为初始值和结束值
        ... //计算对象动画的值
        return value;
    }
}

ValueAnimator.ofObject()总结:
  ValueAnimator.ofObject()本质还是改变值,只是其可以同时改变一个对象的多个属性值。而ValueAnimator.ofInt()和ValueAnimator.ofFloat()只能改变一个值。

ObjectAnimator

  ObjectAnimato和ValueAnimator本质都是通过不断改变View的某个值达到动画效果。不同的是 ValueAnimator是手动给View的某个属性赋值,而ObjectAnimator是自动给View的属性赋值。
  和ValueAnimator类似,ObjectAnimator也有ObjectAnimator.ofInt(),ObjectAnimator.ofFloat(),ObjectAnimator.ofObject()这些类型,具体使用哪种要根据设置的property决定。

具体使用
  java设置:

/**
  Object object:需要操作的对象
  String property:需要操作的对象的属性
  float ....values:动画初始值 & 结束值(不固定长度)
  若是两个参数a,b,则动画效果则是从属性的a值到b值
  若是三个参数a,b,c,则则动画效果则是从属性的a值到b值再到c值
**/
ObjectAnimator animator = ObjectAnimator.ofFloat(Object object, String property, float ....values);

// 设置动画运行的时长
anim.setDuration(500);
// 设置动画延迟播放时间
 anim.setStartDelay(500);
 // 设置动画重复播放次数 = 重放次数+1,动画播放次数 = infinite时,动画无限重复
 anim.setRepeatCount(0);
  // 设置重复播放动画模式:RESTART(默认):正序重放,REVERSE:倒序回放
  anim.setRepeatMode(ValueAnimator.RESTART);

缩放:

//缩放 java代码
fun initAnimator(){
      //作用对象是btn
      //作用的对象属性是x轴缩放
      //动画效果是放大到3倍,在缩小到初始值
      scaleAnimator = ObjectAnimator.ofFloat(btn,"scaleX",1f,3f,2f)
      scaleAnimator.duration = 2000
      scaleAnimator.start()
  }
  
  //xml scale_animator.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
  android:valueFrom="1"
  android:valueType="floatType"
  android:propertyName="scaleX"
  android:valueTo="3"

  android:repeatCount="0"
  android:repeatMode="restart"
  android:startOffset="100"
  android:duration="500">
</objectAnimator>
//java代码中使用xml:
ObjectAniamtor scaleAnimator = ValueAnimatorInflater.loadAnimator(context,R.animtor.scale_animator) as ObjectAnimator
scaleAnimator.target = btn
scaleAnimator.start()

透明度:

//java代码:
fun initAnimator(){
      alphaAnimator = ObjectAnimator.ofFloat(btn,"alpha",1f,0f,0.5f,1f)
      alphaAnimator.duration = 500
      alphaAnimator.repeatCount = 0
      alphaAnimator.repeatMode = ValueAnimator.RESTART
      alphaAniamtor.start()
  }
  
  //xml代码:alpha_animator.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
  android:valueFrom="1"
  android:valueTo="0.5"
  android:valueType="floatType"
  android:propertyName="alpha"

  android:duration="500"
  android:startOffset="100"
  android:repeatMode="restart"
  android:repeatCount="0">

</objectAnimator>

//java 代码:
alphaAnimator = AnimatorInflater.loadAnimator(context,R.animator.alpha_animator) as ObjectAnimator
alphaAnimator.target = btn
alphaAnimator.start()

旋转

//java 代码
fun initAnimator(){
      rotationAnimator = ObjectAnimator.ofFloat(btn,"rotation",0f,360f)
      rotationAnimator.duration = 500
      rotationAnimator.startDelay = 100
      rotationAnimator.repeatMode = ValueAnimator.RESTART
      rotationAnimator.repeatCount = 0
      rotationAniamtor.start()
  }
  
//xml代码:rotation_animator.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
  android:valueFrom="0"
  android:valueTo="360"
  android:valueType="floatType"
  android:propertyName="rotation"

  android:duration="500"
  android:startOffset="100"
  android:repeatCount="0"
  android:repeatMode="reverse">

</objectAnimator>

//java 应用xml代码
  rotationAnimator = AnimatorInflater.loadAnimator(context,R.animator.rotation_animator) as ObjectAnimator
  rotationAnimator.target = btn
  rotationAnimator.start()

平移:平移的坐标系都是以执行动画的View的左上角坐标点为起始点坐标

//java代码:
 fun initAnimator(){
      translateAnimator = ObjectAnimator.ofFloat(btn,"translationX",100F,200F)
      translateAnimator.duration = 500
      translateAnimator.interpolator = BounceInterpolator()
      translationAnimator.start()
  }
  
  //xml 代码
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
  android:valueFrom="0"
  android:valueTo="500"
  android:valueType="floatType"
  android:propertyName="translationX"
  android:interpolator="@android:anim/bounce_interpolator"

  android:duration="500"
  android:startOffset="100"
  android:repeatMode="restart"
  android:repeatCount="0">
</objectAnimator>
//java 应用xml代码
  fun initAniamtorFromXml(){
      translateAnimator = AnimatorInflater.loadAnimator(this,R.animator.translation_animator) as ObjectAnimator
      translateAnimator.target = btn
      translateAnimator.start()
  }

ObjectAnimator在一般View上起作用的集中属性:

View属性值 效果 数值类型
alpha 控制透明度 float
translationX 控制x方向上位移
(以执行动画的View的左上角为坐标原点)
float(例如:0到50)
translationY 控制y方向上位移
(以执行动画的View的左上角为坐标原点)
float(例:如0到500)
scaleX 控制x方向的缩放倍数
(个人认为以View的中心左边点为缩放点)
float(例如:1到3)
scaleY 控制y方向的缩放倍数
(个人认为以View的中心左边点为缩放点)
float(例如:1到3)
rotation 以屏幕方向为轴的旋转 float(例如:0到360)
rotationX 以x轴方向旋转 float(例如:0到360)
rotationY 以y轴方向旋转 float(例如:0到360)

AnimatorSet组合动画

AnimatorSet.play(Animator anim)   :播放当前动画
AnimatorSet.after(long delay)   :将现有动画延迟x毫秒后执行
AnimatorSet.with(Animator anim)   :将现有动画和传入的动画同时执行
AnimatorSet.after(Animator anim)   :将现有动画插入到传入的动画之后执行
AnimatorSet.before(Animator anim) :  将现有动画插入到传入的动画之前执行

xml:

//set_animator.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
   android:ordering="sequentially" >
   // 表示Set集合内的动画按顺序进行
   // ordering的属性值:sequentially & together
   // sequentially:表示set中的动画,按照先后顺序逐步进行(a 完成之后进行 b )
   // together:表示set中的动画,在同一时间同时进行,为默认值

   <set android:ordering="together" >
       // 下面的动画同时进行
       <objectAnimator
           android:duration="2000"
           android:propertyName="translationX"
           android:valueFrom="0"
           android:valueTo="300"
           android:valueType="floatType" >
       </objectAnimator>
       
       <objectAnimator
           android:duration="3000"
           android:propertyName="rotation"
           android:valueFrom="0"
           android:valueTo="360"
           android:valueType="floatType" >
       </objectAnimator>
   </set>

       <set android:ordering="sequentially" >
           // 下面的动画按序进行
           <objectAnimator
               android:duration="1500"
               android:propertyName="alpha"
               android:valueFrom="1"
               android:valueTo="0"
               android:valueType="floatType" >
           </objectAnimator>
           <objectAnimator
               android:duration="1500"
               android:propertyName="alpha"
               android:valueFrom="0"
               android:valueTo="1"
               android:valueType="floatType" >
           </objectAnimator>
       </set>

</set>

android 动画框架

LayoutAnimation

  LayoutAnimation是应用于ViewGroup的动画框架。它可以使VeiwGroup中的childView按照绘制先后,顺序执行动画。
java代码设置

//具体执行的animation:
//animation_layout_scale.xml
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
   android:duration="300"
   android:pivotY="50%"
   android:pivotX="50%"
   android:fromYScale="0.1"
   android:fromXScale="0.1"
   android:toXScale="1"
   android:toYScale="1">
</scale>

//初始化LayoutAnimationControl
Animation animation = AnimationUtils.loadAnimation(mContext,R.anim.animation_layout_scale);
//第一个参数是具体执行的动画,第二个参数是layoutAnimation的延时百分比
LayoutAnimationController controller = new LayoutAnimationControl(animation,0.3f);
//设置动画执行顺序
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
listVeiw.setlayoutAnimation(controller);

xml实现:

//layout_animation.xml
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
   android:delay="0.3"
   android:animationOrder="normal"
   android:animation="@anim/animation_layout_scale">
</layoutAnimation>

//Viewgroup设置LayoutAnimation属性
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
   xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
   android:layout_height="match_parent">
   <ListView
       android:id="@+id/list_view"
       android:layout_width="match_parent"
       android:layoutAnimation="@anim/layout_animation"
       android:layout_height="match_parent"/>
</android.support.constraint.ConstraintLayout>

delay:指的是child view相对于上一个childView动画的延时时间。取值是具体执行的animation的动画时间的倍数;
animationOrder:指的是ViewGroup中child view动画开始的顺序。normal(按照正常的绘制顺序执行),reverse(按照绘制顺序逆序执行),random(随机执行);
animation:child view具体执行的动画,只能是补间动画;

ViewAnimationUtils

  android 5.0以上的生成一个圆形动画的animator;

 private void startViewAniamtionUtils(){
        int centreX = btn.getWidth();
        int centreY = btn.getHeight();
        float hypot = (float) Math.hypot(btn.getHeight(), btn.getWidth());

        //第一个参数是执行圆形动画的view,第二,第三个参数是圆心,第四,第五个参数是圆的半径取值范围
        Animator animator = ViewAnimationUtils.createCircularReveal(btn,centreX,centreY,0,hypot);
        animator.setDuration(600);
        animator.setStartDelay(10);
    //    animator.setInterpolator(new LinearInterpolator());
        AnimatorSet set = new AnimatorSet();
        set.play(animator)
        .with(getAlphAnimator());
        set.setDuration(600);
        set.setInterpolator(new AccelerateInterpolator());
        set.start();
    }
     private ObjectAnimator getAlphAnimator(){
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(btn,"alpha",0f,1f);
        objectAnimator.setDuration(600);
        objectAnimator.setTarget(btn);
    //    objectAnimator.setInterpolator(new LinearInterpolator());
        return objectAnimator;
    }

overridePendingTransition

指定Activity的退出和进入动画,它包括两个部分
一部分是第一个activity退出时的动画,
另外一个部分是第二个activity进入时的动画。
需要注意两个部分:

  • 在android2.0以上调用,
  • 要在startActivity或者finished的后面调用。
  @OnClick(R.id.button)
    public void onViewClicked() {
        finish();
        overridePendingTransition(R.anim.enter_anim,R.anim.exit_anim);
    }

//enter_anim:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fromXDelta="-30%"
    android:toXDelta="0">
</translate>

//exit_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fromXDelta="0"
    android:toXDelta="100%">
</translate>

ViewPropertyAnimator

  本质上和ValueAniamtor和ObjectAnimator相同,能够很方便的为view提供动画。

    button2.animate()
                .translationXBy(200)
                //.translationX(200)
                .setDuration(500);

ViewProperty中带by的方法含义是,相对于执行动画View的现有状态进行动画,不带by的方法含义是相对于View最初始状态进行动画。translationXBy(200)每次执行动画,button2的位置都会相对于现有位置平移200px.translationX(200):不管执行多少次动画,button2的位置都是相对于初始位置平移200px,换句话说button2会在第一次执行动画时平移200px,后面执行动画,button2的位置不会发生变化。

SpringAniamtion

  这是弹簧动画;

  SpringForce spring = new SpringForce(0)
                .setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY)
                .setStiffness(SpringForce.STIFFNESS_LOW);

        new SpringAnimation(rootLayout, DynamicAnimation.TRANSLATION_Y)
                .setSpring(spring)
                .setStartValue(-height)
                .setStartVelocity(-200)
                .start();

SpringAniamtion可以实现旋转,平移,缩放,透明度等的动画。

  • setDampingRatio():设置阻尼系数,取值范围在0 ~ 1之间,值越大弹簧效果越明显。
  • setStiffness(): 设置刚性,取值范围在0 ~ 1之间。值越小,弹簧震动次数也多。