动画|深入浅析

目录

一、View动画

View动画包括:补间动画、逐帧动画。

1.1 补间动画

作用对象:View

动画效果:平移、缩放、旋转、透明度

名称 子类 效果
平移动画 TranslateAnimation 移动View
缩放动画 ScaleAnimation 放大/缩小View
旋转动画 RotateAnimation 旋转View
透明度动画 AlphaAnimation 改变View的透明度

四种动画xml代码

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
        android:shareInterpolator="true"
        android:interpolator = "@android:anim/linear_interpolator">
    <rotate     
        android:fromDegrees="float"
        android:toDegrees="float"
        android:pivotX="float"
        android:pivotY="float" />

    <translate
        android:fromXDelta="float"
        android:fromYDelta="float"
        android:toXDelta="float"
        android:toYDelta="float" />
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float"/>
    <scale
        android:fromXScale="float"
        android:toXScale="float"
        android:fromYScale="float"
        android:toYScale="float"
        android:pivotX="float"
        android:pivotY="float"/>
</set>

以下是对上面代码的说明。

1.set:表示动画集合,对应AnimationSet
  • interpolator:表示动画集合所采用的插值器,影响动画的速度。可以不指定,默认是accelerate_decelerate_interpolate(加速减速插值器)。下文属性动画会详细介绍插值器的相关知识。
  • shareInterpolator:表示集合中的动画是否和集合共享一个插值器。如果集合不指定插值器, 那么子动画就需要单独制定所需的插值器或者使用默认值。
  • fillAfter:表示动画结束时是否保持动画结束时的状态
2.rotate:表示旋转动画,对应RotateAnimation类。
  • fromDegrees:动画起始时物件的角度 (0度指X轴正方向所在方向)
  • toDegrees:动画结束时物件旋转的角度

以上两个属性共同确定旋转方向,原则是:当角度(to-from)为数时表示逆时针旋转,反之。

  • pivotY:动画旋转的轴点的X坐标
  • pivotX:动画旋转的轴点的Y坐标
3.translate:表示平移动画,对应TranslateAnimation
  • android:fromXDelta:动画起始时X坐标上的位置。
  • android:toXDelta:动画结束时X坐标上的位置。
  • android:fromYDelta:动画起始时Y坐标上的位置。
  • android:toYDelta:动画结束时Y坐标上的位置。

注意:以上四个属性以及后面几个类似属性的取值可能是数值、百分数、百分数p,各自含义是:

  • 50:以View左上角为原点沿坐标轴正方向偏移50px。
  • 50%:以View左上角为原点沿坐标轴正方向偏移View宽/高度的50%。
  • 50%p:以View左上角为原点沿坐标轴正方向偏移父(parent)控件宽/高度的50%。区别如图:

偏移属性

4.alpha:表示透明度动画,对应AlphaAnimation
  • fromAlpha:动画起始时透明度
  • toAlpha:动画结束时透明度

以上两个属性值:从0-1中取值。注意:

  • 值=0.0 :表示完全透明
  • 值=1.0 :表示完全不透明
5.scale:表示缩放动画,对应ScaleAnimation
  • fromXScale:动画起始时X坐标上的伸缩尺寸
  • toXScale:动画结束时X坐标上的伸缩尺寸
  • fromYScale:动画起始时Y坐标上的伸缩尺寸
  • toYScale:属性为动画结束时Y坐标上的伸缩尺寸

以上四个属性值的值含义:

  • 值=0.0 :表示收缩到没有
  • 值<1.0 :表示收缩
  • 值=1.0 :表示无伸缩
  • 值>1.0 :表示放大
  • pivotX:动画相对于物件的X坐标的开始位置
  • pivotY:动画相对于物件的Y坐标的开始位置

以上两个属性值表示缩放的轴点:从0%-100%中取值。

1.1.1 单个动画使用

在XML/Java代码中设置,在XML中设置,动画描述的可读性更好。在Java代码中设置,动画效果可动态创建。

以平移动画为例;

XML设置法
  • 步骤1:xml设置

<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000" //动画持续时间
    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="500"// 视图在水平方向x 移动的结束值

    android:fromYDelta="0"// 视图在竖直方向y 移动的起始值
    android:toYDelta="0" // 视图在竖直方向y 移动的结束值
    />
  • 步骤2:java代码
public class MainActivity extends AppCompatActivity {
    Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = findViewById(R.id.button);
        final Animation animation = AnimationUtils.loadAnimation(this,R.anim.animation); //创建动画对象,传入xml文件
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                button.startAnimation(animation); //启动动画
            }
        });
    }
}
  • 效果图

动画效果图

Java代码设置法
        Button mButton = (Button) findViewById(R.id.Button);
        // 步骤1:创建 需要设置动画的 视图View

        Animation translateAnimation = new TranslateAnimation(0,500,0,0);
        // 步骤2:创建平移动画的对象:平移动画对应的Animation子类为TranslateAnimation
        // 参数分别是:
        // 1. fromXDelta :视图在水平方向x 移动的起始值
        // 2. toXDelta :视图在水平方向x 移动的结束值
        // 3. fromYDelta :视图在竖直方向y 移动的起始值
        // 4. toYDelta:视图在竖直方向y 移动的结束值

        translateAnimation.setDuration(3000);
        // 固定属性的设置都是在其属性前加“set”,如setDuration()
        mButton.startAnimation(translateAnimation);
        // 步骤3:播放动画

效果图跟上图一样。

1.1.2 组合动画使用

  • 步骤1:XML设置
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"

android:duration="3000"
android:startOffset ="0"
android:fillBefore = "true"
android:fillAfter = "false"
android:fillEnabled= "true"
android:repeatMode="restart"
android:repeatCount = "0"
android:interpolator = "@android:anim/linear_interpolator">

<rotate  //旋转动画
    android:duration="1000"
    android:fromDegrees="0"// 动画开始时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
    android:toDegrees="360"// 动画结束时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
    android:pivotX="50%"// 旋转轴点的x坐标
    android:pivotY="50%"// 旋转轴点的y坐标
    android:repeatMode="restart"
    android:repeatCount="infinite"
    />

<translate //平移动画
    android:duration="10000"
    android:startOffset ="1000"
    android:fromXDelta="-50%p"
    android:fromYDelta="0"
    android:toXDelta="50%p"
    android:toYDelta="0" />
</set>

  • 步骤2:Java代码设置
public class MainActivity extends AppCompatActivity {
    Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = findViewById(R.id.button);
        final Animation animation = AnimationUtils.loadAnimation(this,R.anim.group_animation); //创建动画对象,传入xml文件
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                button.startAnimation(animation); //启动动画
            }
        });
    }
}
  • 效果图

效果图

1.2 逐帧动画

使用对象:View

原理:将动画拆分为帧的形式,且定义每一帧 = 每一张图片

本质:顺序播放一组预先定义好的图片

使用

  • 步骤1: 在res/anim文件夹中创建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"/>
    </animation-list>
    
  • 步骤二:在Java代码中设置

 Button button = findViewById(R.id.button);
                 button.setBackgroundResource(R.drawable.frame_animation);
                 
AnimationDrawable animationDrawable = (AnimationDrawable) button.getBackground();
  animationDrawable.start(); //启动动画

优点:使用简单、方便

缺点:容易引起OOM,当使用大量 和尺寸较大的图片资源时。

二、属性动画

说明:属性动画(Property Animation)是在 Android 3.0API 11)后才提供的一种全新动画模式。

Q:为什么要提供属性动画?

  • View动画作用对象局限于View,而属性动画能作用于任意Java对象。
  • View动画只是改变了View的视觉效果,没有改变View的属性,属性动画可以改变对象的属性。
  • View动画效果单一,属性动画效果更加丰富。
View动画 属性动画
作用对象 View 任何对象,甚至没有对象
属性改变 没有改变属性 改变了属性
动画效果 效果单一 效果丰富

属性改变说明:比如将屏幕左上角的按钮通过补间动画移动到屏幕右下角,点击当前按钮位置(右下角)是没有效果的,实际上按钮还是停留在左上角,补间动画只是将按钮绘制到屏幕右下角,改变了视觉效果而已。

2.1 使用

同样的,属性动画可以在xml设置实,也可以在代码中设置实现。建议用代码实现:

  • 代码实现比较简单。
  • 属性的起始值有时候无法确定,需要动态地创建属性动画。

下面是组合动画旋转+平移实例。

Java 设置

 button = findViewById(R.id.button);
        // 步骤1:设置需要组合的动画效果
        // 平移动画

        ObjectAnimator translation = ObjectAnimator.ofFloat(button, "translationX", 0, 300);
        translation.setRepeatCount(0);

        // 旋转动画
        ObjectAnimator rotate = ObjectAnimator.ofFloat(button, "rotation", 0f, 360f);


        // 步骤2:创建组合动画的对象
        final AnimatorSet animSet = new AnimatorSet();

        // 步骤3:根据需求组合动画
        animSet.play(translation).with(rotate);
        // 步骤4:启动动画
		animSet.start(); 

XML设置

  • 步骤1: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>
  • Java代码设置
AnimatorSet set = (AnimatorSet)AnimatorInflater.loadAnimator(this,R.anim.property_animator);
set.setTarget(button); //设置动画作用对象
set.start();//启动动画
  • 效果图

效果图

2.2 插值器与估值器

类型 定义 作用 应用场景 备注
插值器 辅助动画实现的接口 设置属性值从初始值过渡到结束值的变化规律 实现非线性运动的动画效果 内置9种插值器/自定义插值器实现
估值器 辅助动画插值器的接口 设置属性值从初始值过渡到结束值的变化具体数值 协助插值器 实现非线性运动的动画效果 内置3种估值器/自定义估值器实现

插值器

 //xml设置
 android:interpolator="@android:anim/overshoot_interpolator"
 //Java代码设置
 Interpolator overshootInterpolator = new OvershootInterpolator();
 animation.setInterpolator(overshootInterpolator);

9种内置插值器

9种插值器效果图

估值器

  • 作用:根据当前属性改变的百分比计算出改变后的属性值
  • 常用的系统内置的估值器:
  • 整型估值器(IntEvaluator)
  • 浮点型估值器(FloatEvaluator)
  • Color属性估值器(ArgbEvaluator)
  • 仅针对于属性动画,View动画不需要类型估值器。是属性动画实现非匀速动画的重要手段。
  • 自定义插值器方法:实现 Interpolator / TimeInterpolator接口 ,然后复写getInterpolation()
  • 自定义估值器方法:实现TypeEvaluator接口,然后复写evaluate()

推荐一篇插值器估值器的详细用法Android 动画:你真的会使用插值器与估值器吗?(含详细实例教学)

2.3 监听器

      Animation.addListener(new AnimatorListener() {
          @Override
          public void onAnimationStart(Animation animation) {
              //动画开始时执行
          }
      
           @Override
          public void onAnimationRepeat(Animation animation) {
              //动画重复时执行
          }

         @Override
          public void onAnimationCancel()(Animation animation) {
              //动画取消时执行
          }
    
          @Override
          public void onAnimationEnd(Animation animation) {
              //动画结束时执行
          }
      });

// 特别注意:每次监听必须4个方法都重写。

Q:有些时候我们并不需要监听动画的所有时刻,不想写太多代码怎么办?

采用动画适配器(AnimatorListenerAdapter)。

anim.addListener(new AnimatorListenerAdapter() {  
// 向addListener()方法中传入适配器对象AnimatorListenerAdapter()
// 由于AnimatorListenerAdapter中已经实现好每个接口
// 所以这里不实现全部方法也不会报错
    @Override  
    public void onAnimationStart(Animator animation) {  
    // 如想只想监听动画开始时刻,就只需要单独重写该方法就可以
    }  
});  

三、总结

总结

ObjectAnimatorValueAnimator类的区别:

  • ValueAnimator 类是先改变值,然后 手动赋值 给对象的属性从而实现动画;是 间接 对对象属性进行操作;
  • ObjectAnimator 类是先改变值,然后 自动赋值 给对象的属性从而实现动画;是 直接 对对象属性进行操作;

ValueAnimator类自动赋值的逻辑:

  1. 初始化时,如果属性的初始值没有提供,则调用属性的 get()进行取值;
  2. 当 值 变化时,用对象该属性的 set()方法,从而从而将新的属性值设置给对象属性。
  • ObjectAnimator 类针对的是任意对象 & 任意属性值,并不是单单针对于View对象
  • 如果需要采用ObjectAnimator 类实现动画效果,那么需要操作的对象就必须有该属性的set() & get()
  • 同理,针对上述另外的三种基本动画效果,View 也存在着setRotation()getRotation()setTranslationX()getTranslationX()setScaleY()getScaleY()set() & get()

本文参考自:

猜你喜欢

转载自blog.csdn.net/qq_44830568/article/details/109059720