Android的动画可以分为三种:View动画帧动画属性动画。

  • View动画包括:平移、旋转、缩放、透明度。不会改变控件坐标参数
  • 帧动画:图片切换动画。不会改变控件坐标参数
  • 属性动画:通过动态改变控件的属性(改变控件部分坐标参数)达到动画效果。

一 View动画的创建步骤和方式

TranslateAnimationRotateAnimationScaleAnimationAlphaAnimation。这四种动画既可以通过XML来定义,也可以通过代码来动态创建。他们的集成关系如下:


通过xml去创建动画的步骤:

1.在res文件夹下创建anim文件夹 

2.在anim文件夹下去创建动画xml文件

3.通过AnimationUtils类的静态方法loadAnimation获取动画对象

4.通过View.startAnimation()方法开启动画;

通过代码去创建动画的步骤(这里不写具体的步骤):

1.创建TranslateAnimation、RotateAnimation、ScaleAnimation或AlphaAnimation对象;

2.设置创建的动画对象的属性,如动画执行时间、延迟时间、起始位置、结束位置等;

3.通过View.startAnimation()方法开启动画;

二 TranslateAnimation动画

创建一个动画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:fromYDelta="0"
    android:toXDelta="300"
    android:toYDelta="300" />复制代码

解释一下属性:

这里的坐标系是以控件自身的左上角为坐标原点,右下为正方向的坐标系

android:fromXDelta:动画开始时候X方向的坐标

android:fromYDelta:动画开始时候Y方向的坐标

android:toXDelta:动画结束时候X方向的坐标

android:toYDelta:动画结束时候Y方向的坐标

它们的值不仅可以指定像素,而且还可以指定百分比,且坐标系的原点不会改变!

相对于自身可以指定像这样:

android:toXDelta="100%"复制代码

相对于父控件可以指定像这样

android:toXDelta="100%p"复制代码

 android:duration:一个动画周期持续时间,单位是ms

 android:fillAfter :设置为true,动画结束时,将保持动画最后时的状态

 android:fillBefore :设置为true,动画结束时,还原到开始动画前的状态,默认值

 android:repeatCount :重复次数,想让永远设置成-1

android:repeatMode :重复类型,有reverse和restart两个值,reverse表示倒序回放,restart表示重新放一遍,必须与repeatCount一起使用才能看到效果。因为这里的意义是重复的类型,即回放时的动作。默认不写是restart效果

android:startOffset:动画延迟执行的时间,单位是ms

android:interpolator:动画插值器,改变动画播放速率

插值器的值有:

@android:anim/accelerate_interpolator:加速变化(开始慢,越来越快)

@android:anim/decelerate_interpolator:减速变化(开始快,越来越慢)

@android:anim/accelerate_decelerate_interpolator:先加速后减速(中间速度最快)

@android:anim/linear_interpolator:线性均匀变化

@android:anim/overshoot_interpolator:超出结尾的临界值,然后在缓慢回到结束值

@android:anim/anticipate_interpolator:先向相反的方向改变一点,然后加速变化

@android:anim/anitcipate_overshoot_interpolator:先向相反的方向改变一点,然后在加速播放至超出结束值一点,然后在缓慢回到结束值

@android:anim/bounce_interpolator:动画快结束的时候,模拟球落地的回弹效果

@android:anim/cycle_interpolator:反方向在做一次动画效果

代码加载xml去开启动画代码:

//加载xml动画
val translate1 = AnimationUtils.loadAnimation(this, R.anim.translate1)
//给控件设置动画并开启
btn.startAnimation(translate1)复制代码

RotateAnimation动画

创建一个动画xml文件


<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fromDegrees="0"
    android:toDegrees="-300"
    android:pivotX="50%"
    android:pivotY="50%">

</rotate>复制代码

解释一下属性:

这里的夹角是和Y轴的夹角,顺时针为正,逆时针为负,坐标系还是当前控件的左上角为原点

android:fromDegrees:开始动画的角度

android:toDegrees:结束时候的角度

android:pivotY,android:pivotX:旋转的中心点坐标,不写是控件的左上角原点为中心点

其余的属性和平移动画一样,不再重复

四 ScaleAnimation动画

创建一个动画xml文件

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fromXScale="0.0"
    android:fromYScale="0.0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toXScale="1.5"
    android:toYScale="1.5">

</scale>复制代码

解释一下属性:

坐标系还是当前控件的左上角为原点

android:fromYScale,android:fromXScale:开始缩放比例

android:toXScale, android:toYScale:结束缩放比例

android:toYScale,android:pivotY:缩放中心点

其余的属性和平移动画一样,不再重复

五AlphaAnimation动画


<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:fromAlpha="1.0"
    android:toAlpha="0.0">

</alpha>复制代码

解释一下属性:

android:fromAlpha:动画开始时候透明度

android:fromAlpha:动画结束时候透明度

其余的属性和平移动画一样,不再重复

六组合到一起

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="10000">

    <translate
        android:fromXDelta="0"
        android:fromYDelta="0"
        android:toXDelta="0"
        android:toYDelta="300" />

    <rotate
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="300" />

    <scale
        android:fromXScale="0"
        android:fromYScale="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="1"
        android:toYScale="1" />
    <alpha
        android:fromAlpha="0"
        android:toAlpha="1" />
</set>复制代码

这里有两个细节需要注意:

  • 如果我们给set设置了共有的属性,那么它包裹的动画再次设置这个属性也不会生效,都会以跟属性为准。
  • 但是插值器可以单独设置,需要配合android:shareInterpolator一起设置,表示集合中的动画是否和集合共享同一个插值器。
  • 如果不想让组合动画同时执行,我们可以通过设置动画的延迟时间去改变不去同时执行,它并没有像属性动画那样给我们提供设置执行先后顺序的方法。

七View动画的监听

val loadAnimation = AnimationUtils.loadAnimation(this, R.anim.enter)
loadAnimation.setAnimationListener(object : Animation.AnimationListener {
    //动画完全结束时候调用
    override fun onAnimationEnd(animation: Animation?) {

    }

    //动画开始时候调用
    override fun onAnimationStart(animation: Animation?) {
    }

    //动画重复时候调用
    override fun onAnimationRepeat(animation: Animation?) {

    }
})复制代码

八帧动画

帧动画是顺序播放一组预先定义好的图片,类似于电影播放。帧动画创建的文件在drawable文件夹下。需要用到的类是AnimationDrawable。它的继承关系如下:




<?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/d_beishang" android:duration="500" />
    <item android:drawable="@drawable/d_bishi" android:duration="500" />
    <item android:drawable="@drawable/d_bizui" android:duration="500" />
    <item android:drawable="@drawable/d_chanzui" android:duration="500" />

</animation-list>复制代码
//把定义的帧动画设置给控件
btn.setBackgroundResource(R.drawable.donghua);
//获取控件中的帧动画
var anim = btn.background as AnimationDrawable
//开启帧动画
anim.start()复制代码

解释: android:oneshot属性表示是否重复动画,

注意:帧动画的使用比较简单,但是比较容易引起OOM。

九view动画常见应用场景

8.1 5.0版本之前Activity切换动画

主要用到 overridePendingTransition(int enterAnim,int exitAnim)这个方法,这个方法必须在 startActivity(Intent)或者finish()之后被调用才能生效。这里自定义的view动画设置到里边就能替换原生系统的切换动画。

延伸:5.0版本之后google对于切换界面动画提供了新的方式:

8.2给ViewGroup的子控件加进场动画

这种效果需要用到layoutAnimation类,步骤如下:

1.创建res/anim下view动画

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="0"
        android:toXDelta="0"
        android:fromYDelta="100%"
        android:toYDelta="0"
        android:duration="2000" />
    <alpha
        android:fromAlpha="0"
        android:toAlpha="1"
        android:duration="2000" />
</set>复制代码

2.在res/anim下创建layoutAnimation

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

</layoutAnimation>复制代码

解释属性:

 android:delay:可以取值为数值,百分数,或百分数p。表示两个子控件执行出场动画的间隔时间,为0时,所有控件的动画没有延迟全部开始执行;为1时表示等上一个控件动画执行完毕才开始执行下一个

 android:animationOrder:有三个值::normal表示按正常顺序出现。random表示乱序出现。reverse表示反序出现。

 android:animation:指定出现时要执行的view动画

3.给viewGroup设置layoutAnimation的值

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layoutAnimation="@anim/layout_viewgrop"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

      ...
</LinearLayout>复制代码

同时可以用代码设置子view的动画:

//加载组定义的view动画
val loadAnimation = AnimationUtils.loadAnimation(this, R.anim.anim_layout)
//创建动画控制器
val Controller = LayoutAnimationController(loadAnimation)
//设置每个子view动画间隔
Controller.delay=0.5F
//设置动画播放顺序
Controller.order = LayoutAnimationController.ORDER_NORMAL
//把动画设置给父控件
viewGroup.layoutAnimation = Controller复制代码