动画类型

View Animation(视图动画)

  • Tween Animation(补间动画)
  • Frame Animation(逐帧动画)

Property Animation(属性动画)

  • ValueAnimator
  • ObjectAnimator

一. 视图动画标签

1.概述

Android动画由5种类型组成:alpha、scale、translate、rotate、set

1.1配置XML动画文件

常用标签:

  • alpha:渐变透明度动画
  • scale:渐变尺寸伸缩动画
  • translate:画面变换位置移动动画
  • rotate:画面转移旋转动画
  • set:定义动画集
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="0.0"
android:toXScale="1.4"
android:fromYScale="0.0"
android:toYScale="1.4"
android:pivotX="50%"
android:pivotY="50%"
android:duration = "1000">
</scale>

1.2 动画文件存放位置

动画文件应该放于res/anim文件夹下,访问时使用R.anim.XXX

1.3 使用动画文件

Animation animation = AnimationUtils.loadAnimation(MainActivity.this,R.anim.scale_down_anim);
textView.startAnimation(animation);
//textView.clearAnimation();

动画开始时,会将TextView的高度、宽度都从0缩放到1.4倍大小

1.4 scale标签

scale标签用于缩放动画,该标签有如下几个属性

  • android:fromXScale:动画起始时,控件在X轴方向相对自身的缩放比例,浮点值,比如,1.0代表自身无变化,0.5代表缩放1倍,2.0代表放大1倍
  • android:toXScale:动画结束时,控件在X轴相对自身的缩放比例,浮点值。
  • android:fromYScale:动画起始时,控件在Y轴方向相对自身的缩放比例,浮点值。
  • android:toYScale:动画结束时,控件在Y轴方向相对自身的缩放比例,浮点值。
  • android:pivotX:缩放起始点X轴坐标,可以是数值、百分数、百分数p 三种样式,如50、50% 、50%p 。如果是数值, 表示在当前视图的左上角 ,即原点处加 50px,作为缩放起始点X轴坐标;如果是 50% 则表示在当前控件的左上角加上自己宽度的50%作为缩放起点X轴坐标;如果是50%p,则表示在当前父控件的左上角加上父控件宽度的50%作为缩放起始点X轴坐标。
  • android:pivotY:缩放起始点X轴坐标,取值及含义与 android:pivotX相同。
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="0.0"
android:toXScale="1.4"
android:fromYScale="0.0"
android:toYScale="1.4"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="true"
android:duration="2000"/>

1.5 Animation继承属性

所有的动画都继承Animation

scale标签为例,讲述Animation类所具有的属性及其含义

  • android:duration:用于设置一次动画的持续时间,以毫秒为单位。
  • android:fillAfter:如果设置为 true,则控件动画结束时,将保持动画结束时的状态。
  • android:fillBefore:如果设置为 true,则控件动画结束时,将还原到初始化状态。
  • android fil!Enabed:与android:fillBefore 效果相同,都是在控件动画结束时,将还原到初始化状态。
  • android:repeatCount:用于指定动画的重复次数,当取值为infinite 时, 表示无限循环。
  • android:repeatMode:用于设定重复的类型,有 reverse和restart两个值,其中reverse表示倒序回放: restart 表示重放,并且必须与- repeatCount 一起使用才能看到效果。
  • android:interpolator:用于设定插值器,其实就是指定的动画效果,比如弹跳效果等。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true"
>
<scale android:fromXScale="1.0"
android:toXScale="0.4"
android:fromYScale="1.0"
android:toYScale="0.6"
android:pivotY="50%"
android:pivotX="50%"
android:repeatMode="reverse"
android:repeatCount="2"
android:duration="700"/>
</set>

1.6 alpha标签

标签属性:

  • android:fromAlpha: 动画开始时的透明度,取值范围为 0~ 1 .0, 0.0表示全透明, 1.0表示完全不透明。
  • android:toAlpha: 动画结束时的透明度
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:fillBefore="true">
<alpha android:fromAlpha="1.0"
android:toAlpha="0.1"
/>
</set>

1.7 rotate标签

rotate标签用于实现画面转移旋转动画效果,标签属性:

  • android:fromDegress:动画开始旋转时的角度位置,正值代表顺时针方向的度数,负值代表逆时针方向的度数
  • android:toDegress:动画结束时旋转到的角度位 ,正值代表顺时针方向的度数,负值代表逆时针方向的度数
  • android:pivotX:旋转中心点X轴坐标,默认旋转中心点是控件坐标原点。 可以是数值、百分数、 百分数p 三 种样式,比如 50 50% 50%p ,具体含义己在 scale 标签中讲述。
  • android:pivotY:旋转中心点Y轴坐标。
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="6000"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="1080" />
<!-- android:repeatCount="infinite"-->
<!-- android:repeatMode="restart"-->
<!-- 以中心点顺时针旋转3圈-->

1.8 translate标签

translate标签用于实现画面变换位置移动动画效果。属性:

  • android:fromXDelta:起始点X轴坐标,可以是是数值、百分数、百分数p 三种样式。
  • android:fromYDelta:起始点Y轴坐标
  • android:toXDelta:终点X轴坐标
  • android:toYDelta:终点Y轴坐标
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<!--控件从点(0,0)移动到(-80,-80)-->
<translate
android:duration="2000"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="-80"
android:toYDelta="-80" />
</set>

1.9 set标签

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:fillAfter="true">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0" />
<scale
android:fromXScale="0.0"
android:fromYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.4"
android:toYScale="1.4" />
<rotate
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="720" />
</set>

控件完成了从小到大,旋转出场,透明度从0到1的组合效果。

注意:在 set 标签中设直 repeateCount 属性是无效的,必须对每个动画单独设直才有作用

二、视图动画的代码实现

标签与所对应的类如下所示

scale ScaleAnimation
alpha AlphaAnimation
rotate RotateAnimation
translate TranslateAnimation
set AnimationSet

2.1 ScaleAnimation

与1.4节XML对应的代码是:

Animation scaleAnimation = new ScaleAnimation(
0,1.4f,0,1.4f,
Animation.RELATIVE_TO_SELF,0.5f,
Animation.RELATIVE_TO_SELF,0.5f);
scaleAnimation.setDuration(2000);
scaleAnimation.setFillAfter(true);

2.2 AlphaAnimation

与1.6节对应的代码是:

Animation alphaAnimation = new AlphaAnimation(0.0f,1.0f);
alphaAnimation.setDuration(3000);
alphaAnimation.setFillBefore(true);

2.3 RotateAnimation

与1.7节对应的代码是:

Animation rotateAnimation = new RotateAnimation(0,1080,
Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
rotateAnimation.setDuration(6000);

2.4 TranslateAnimation

与1.8节对应的代码是:

Animation translateAnimation = new TranslateAnimation(0,-80,0,-80);
translateAnimation.setDuration(2000);

2.5 AnimationSet

与1.9对应的代码是:

//创建AnimationSet对象
AnimationSet animationSet = new AnimationSet(true);
//创建动画对象
Animation alphaAnimation = new AlphaAnimation(0.0f,1.0f);
Animation scaleAnimation = new ScaleAnimation(0.0f,1.4f,0.0f,1.4f,
Animation.RELATIVE_TO_SELF,0.5f,
Animation.RELATIVE_TO_SELF,0.5f);
Animation rotateAnimation = new RotateAnimation(0,720,
Animation.RELATIVE_TO_SELF,0.5f,
Animation.RELATIVE_TO_SELF,0.5f);
//添加动画到AnimationSet
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(scaleAnimation);
animationSet.addAnimation(rotateAnimation);
//设置属性
animationSet.setDuration(3000);
animationSet.setFillAfter(true);
binding.textView.startAnimation(animationSet);

2.7 Animation

其他函数

void cancel() //取消动画
void reset() //将控件重置到动画开始前状态
void setAnimationListener(Animation.AnimationListener listener) //设置动画监听

示例:

animationSet.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}

@Override
public void onAnimationEnd(Animation animation) {
animationSet.reset();
showTranslateAnimation(); //展示移动动画 2.4节
}
@Override
public void onAnimationRepeat(Animation animation) {

}
});

三、 插值器

插值器是在 XML 中定义的动画修改器,它会影响动画的变化率。插值器可对现有的动画效果执行加速、减速、重复、退回等。

插值器通过 android:interpolator 属性应用于动画元素,该属性的值是对插值器资源的引用。

Android 中提供的所有插值器都是 Interpolator 类的子类。为便于您使用 android:interpolator 属性将插值器应用于动画,Android 针对每个插值器类包含了一个可供您引用的公共资源。下表指定了每个插值器要使用的资源:

插值器类 资源 ID
AccelerateDecelerateInterpolator @android:anim/accelerate_decelerate_interpolator
AccelerateInterpolator @android:anim/accelerate_interpolator
AnticipateInterpolator @android:anim/anticipate_interpolator
AnticipateOvershootInterpolator @android:anim/anticipate_overshoot_interpolator
BounceInterpolator @android:anim/bounce_interpolator
CycleInterpolator @android:anim/cycle_interpolator
DecelerateInterpolator @android:anim/decelerate_interpolator
LinearInterpolator @android:anim/linear_interpolator
OvershootInterpolator @android:anim/overshoot_interpolator

您可以通过以下方式使用 android:interpolator 属性应用上述某个插值器:

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

自定义插值器

如果您对平台提供的插值器(在上表中列出)不满意,则可以使用修改过的属性创建自定义插值器资源。例如,您可以调整 AnticipateInterpolator 的加速率或调整 CycleInterpolator 的循环次数。为此,您需要在 XML 文件中创建自己的插值器资源。

文件位置:

res/anim/*filename*.xml
该文件名将用作资源 ID。

编译后的资源数据类型:

指向相应插值器对象的资源指针。

资源引用:

在 XML 中:@[*package*:]anim/*filename*

语法:

<?xml version="1.0" encoding="utf-8"?>
<InterpolatorName xmlns:android="http://schemas.android.com/apk/res/android"
android:attribute_name="value"
/>

如果您不应用任何属性,则您的插值器的运作方式将与平台提供的插值器(在上表中列出)完全相同。

元素:

请注意,在 XML 中定义的每个 Interpolator 实现的名称都以小写字母开头。

  • <accelerateDecelerateInterpolator>

    变化率在开始和结束时缓慢,但在中间会加快。无属性。

  • <accelerateInterpolator>

    变化率在开始时较为缓慢,然后会加快。属性:android:factor浮点数。加速率(默认为 1)。

  • <anticipateInterpolator>

    先反向变化,然后再急速正向变化。属性:android:tension浮点数。要应用的张力(默认为 2)。

  • <anticipateOvershootInterpolator>

    先反向变化,再急速正向变化并超过目标值,然后以最终值结束。属性:android:tension浮点数。要应用的张力(默认为 2)。android:extraTension浮点数。张力要乘以的倍数(默认值为 1.5)。

  • <bounceInterpolator>

    变化会在结束时退回。无属性。

  • <cycleInterpolator>

    按指定的循环次数重复动画。变化率符合正弦曲线图。属性:android:cycles整数。循环次数(默认值为 1)。

  • <decelerateInterpolator>

    变化率开始时很快,然后减慢。属性:android:factor浮点数。减速率(默认值为 1)。

  • <linearInterpolator>

    变化率恒定不变。无属性。

  • <overshootInterpolator>

    先急速正向变化,再超过最终值,然后回到最终值。属性:android:tension浮点数。要应用的张力(默认为 2)。

示例:

保存在 res/anim/my_overshoot_interpolator.xml 的 XML 文件:

<?xml version="1.0" encoding="utf-8"?>
<overshootInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:tension="7.0"
/>

此动画 XML 将应用插值器:

<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@anim/my_overshoot_interpolator"
android:fromXScale="1.0"
android:toXScale="3.0"
android:fromYScale="1.0"
android:toYScale="3.0"
android:pivotX="50%"
android:pivotY="50%"
android:duration="700" />

四、动画示例

4.1 镜头由远及近效果

ScaleAnimation scaleAnimation = new ScaleAnimation(1f,1.1f,1f,1.1f,
Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
scaleAnimation.setDuration(3*1000L);
scaleAnimation.setFillAfter(true);
binding.imageView.setAnimation(scaleAnimation);

AlphaAnimation alphaAnimation = new AlphaAnimation(0.5f,1.0f);
alphaAnimation.setDuration(3 * 1000L);
alphaAnimation.setFillAfter(true);
binding.ivSlogan.setAnimation(alphaAnimation);
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SplashActivity">

<ImageView
android:id="@+id/imageView"
android:background="@drawable/bg_splash"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/app_name" />

<TextView
android:id="@+id/slogan_bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="44dp"
android:text="@string/slogan_txt"
android:textColor="@color/white"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

<TextView
android:id="@+id/slogan_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
android:text="@string/slogan_top_text"
android:textColor="@color/white"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/slogan_bottom"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

<ImageView
android:id="@+id/ivSlogan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="80dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_logo_slogan" />

</androidx.constraintlayout.widget.ConstraintLayout>

动画效果

动画效果

4.2 Loading动画效果

RotateAnimation rotateAnimation = new RotateAnimation(0,360f,
Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
rotateAnimation.setDuration(1500);
rotateAnimation.setRepeatCount(-1);
rotateAnimation.setRepeatMode(Animation.RESTART);
rotateAnimation.setInterpolator(new LinearInterpolator());

4.3 扫描动画

动画文件

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000">
<scale
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="infinite"
android:toXScale="3.0"
android:toYScale="3.0" />
<alpha
android:fromAlpha="0.4"
android:repeatCount="infinite"
android:toAlpha="0.0" />
</set>
Animation animationSet1 = getScanAnimation();
Animation animationSet2 = getScanAnimation();
animationSet2.setStartOffset(750);
Animation animationSet3 = getScanAnimation();
animationSet3.setStartOffset(1500);
Animation animationSet4 = getScanAnimation();
animationSet4.setStartOffset(2250);

binding.startScan.setOnClickListener(view -> {
binding.circle1.startAnimation(animationSet1);
binding.circle2.startAnimation(animationSet2);
binding.circle3.startAnimation(animationSet3);
binding.circle4.startAnimation(animationSet4);
});

private Animation getScanAnimation(){
return AnimationUtils.loadAnimation(this,R.anim.scan_anim);
}

五、逐帧动画

示例:

res/Drawable文件下新建动画文件:

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item
android:drawable="@drawable/a1"
android:duration="80" />
<item
android:drawable="@drawable/a2"
android:duration="80" />
<item
android:drawable="@drawable/a3"
android:duration="80" />
</animation-list>

在代码中使用:

AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getBackground();
animationDrawable.start();

android:oneshot 如果是false,表示无限循环,true表示只展示一次

5.1 AnimationDrawable类

在Android中,逐帧动画需要得到AnimationDrawable类的支持,它位于android.graphics.drawable包下,是Drawable的间接子类。它主要用来创建一个逐帧动画,并且可以对帧进行拉伸,把它设置为View的背景。

AnimationDrawable的常用函数:

void start() //开始播放逐帧动画
void stop() //停止播放逐帧动画
int getDuration(int i) //得到指定index帧的持续时间
int getNumberOfFrames() //得到当前AnimationDrawable所有的帧的数量
Drawable getFrame(int index) //得到指定index的帧对应的Drawable对象
boolean isRunning() //判断当前AnimationDrawable是否正在播放
void setOneShot(boolean oneShot) //设置AnimationDrawable是否执行一次,返回true,表示执行一次,返回false,表示无限循环
boolean isOneShot() //判断AnimationDrawable是否执行一次,返回true,表示执行一次,返回false,表示无限循环
void addFrame(@NonNull Drawable frame, int duration) //为AnimationDrawable添加一帧,并设置持续时间