视图动画-View Animation

1、What is View Animation

视图动画主要有两种:
一、Tween Animation译为“补间动画”
1、scale译为“规模、比例”,是对View进行特定范围的缩放
2、alpha通过改变View的透明度实现View隐现的效果
3、translate译为”转移”,是对View进行位置的移动
4、rotate译为“旋转”,是让View围绕特定的点进行旋转
PS:所有View的移动、隐藏、旋转仅仅是看到的动画效果,实际View的位置/大小/比例并没有发生本质上的改变(比如说View的位置通过动画进行移动后你注册的点击事件还是需要点击到View的原始位置才可以被触发)。
二、Frame Animation译为逐帧动画
这个比较容易理解就是将多个具有特定连贯动作的图片在短时间内进行快速的切换达到动画的效果,本质上所有的动画效果都是这种思想。

2、如何创建视图动画文件目录

动画文件要存放在res/anim文件夹下,访问时采用R.anim.XXX的方式。默认是没有这个文件夹的需要手动创建(右键res目录–>New–>Android Resource Directory–>确定。)

image

动画文件的创建方式为:右键anim文件夹选择new,然后点击Animation Resource file,选择动画类型即可创建。
image

输入后会自动提示动画名称,然后输入名称,确定即可。

image

scale(缩放) 动画

这个动画参数相对来说比较多, 就我个人而言在学习这个动画的时候花费时间是最长的。这个动画主要是实现View的缩放,首先要想,要实现一个缩放的动画首先要确定什么参数/信息(好比说想切割一张特定大小的纸张要确定宽和高一样),那么第一个就是要确定要围绕哪个点(pivot)进行缩放。还需要知道在动画开始(from)时View的大小(比例),以及动画结束(to)时View要处于的大小(比例)。就是要确定以下六个参数才可以完成一次缩放动画。

X则指定控件的宽度,Y则指定控件的高度,值越大则控件所占位置越大。Android坐标从左上角开始算起。

参数名称 说明
pivotX 动画开始时View所处的X轴坐标
pivotY 动画开始时View所处的Y轴坐标
fromXScale 在播放View动画时,这个View的起始的X轴坐标的长度(比例)
toXScale 在播放View动画到最后时,这个View的X轴坐标所要达到的长度(比例)
fromYScale 在播放View动画时,这个View的起始的Y轴坐标的长度(比例)
toYScale 在播放View动画到最后时,这个View的Y轴坐标所要达到的高度(比例)

其中fromXScaletoXScalefromYScaletoYScale使用浮点类型,1.0表使原始大小,0.5则是缩放一半,1.5则是扩大原大小的一半。举例:原View宽高100、150,1.0:(100,150),0.5:(50,75),1.5:(150,225)。也可以使用精确值(DP/PX)。

pivotXpivotY有三种表使方法,第一是采用像素值,第二则是较自身的百分比,第三则是较父View的百分比。

为了方便观察,使用两个同等位置和大小不同颜色的View来进行观察。动画的播放代码在最下文已给出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button android:layout_width="match_parent" android:layout_height="wrap_content"
android:text="播放动画"
android:id="@+id/btnOpenAnimation"
/>
<TextView android:layout_width="300dp" android:layout_height="300dp"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:background="#03A9F4"/>
<TextView android:layout_width="300dp" android:layout_height="300dp"
android:layout_centerInParent="true"
android:id="@+id/txtAnimation"
android:layout_gravity="center"
android:background="#FF00"/>
</RelativeLayout>

示例1:使用像素值确定Pivot点

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="0.5"
android:toXScale="1.0"
android:duration="3000"
android:fromYScale="0.5"
android:toYScale="1.0"
android:pivotX="200"
android:pivotY="200">
</scale>

这里我们分别设置了pivotXpivotY为200(px),这个是从View本身来算起的,View的左上角为(0,0)点,然后X轴坐标向右,Y则向下分别走200像素,最终得到了箭头指向的点(Pivot),那么开始点确定了。再看其它参数,fromXScale指定的是在动画开始时X坐标也就是宽度的大小(这里是按照比例计算的),0.5则代表View原始宽度的一半,fromYScale则是高度了。既然是向特定的比例进行缩放,仅仅确定开始的大小是不够的,还要确定在动画播放到最后所要达到的大小,所以就有了toXScaletoYScale,这两个则是指定在动画播放完成后View所处的大小。这里我们是从View的0.5缩放到1.0,也就是从原始View的一半经过3秒(duration用来控制动画时长,1000为1秒。)后变成原始View的大小也就是1.0。

image

image

示例2:百分比Pivot

使用百分比确定Pivot也很简单,那么Pivot的位置就是:以View的左上角即(0,0)点为基础加上View特定的宽高百分比。

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="0.0"
android:toXScale="1.0"
android:duration="5000"
android:fromYScale="0.0"
android:toYScale="1.0"
android:pivotX="70%"
android:pivotY="70%">
</scale>

image

image

示例3:父View百分比Pivot

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="0.0"
android:toXScale="1.0"
android:duration="5000"
android:fromYScale="0.0"
android:toYScale="1.0"
android:pivotX="50%p"
android:pivotY="50%p">
</scale>

这个计算和上边那个其实是一样的,只是基于的点不同而已,上边是基于自身来算起,那么这个则是基于View的父布局来计算的。那么Pivot的位置就是:以View的左上角即(0,0)点为基础加上父View特定的宽高百分比。

image

image

alpha动画

这个可以说就非常简单了,主要是实现颜色的过度效果,fromAlpha则是动画开始的透明度,toAlpha则是在动画最后显示的透明度。0.0代表完全透明1.0则是View的原色。

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="0.0"
android:duration="3000"
android:toAlpha="1.0">
</alpha>

image

rotate(旋转) 动画

首先要想完成旋转要确定那些参数?肯定要确定旋转要围绕的点也就是pivot,这个在scale动画也用到了,用法都一样,不在多说。这里出现了名为degrees也就是角度的概念,也就是以特定点(pivot)为中心从多少度(fromDegrees),旋转到多少度(toDegrees)。以下示例是从0转到360度,正好一圈。

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotY="50%"
android:pivotX="50%"
android:duration="3000"
>
</rotate>

image

translate(位移) 动画

说白了就是移动View的位置,就是从一个点移动到另一个点,最重要的就是确定两个点,那么则需要确定两对X,Y坐标了。以下参数的使用方式和在最上边提到的pivot是一样的都可以使用精确值和百分比。

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="10%"
android:toXDelta="70%"
android:fromYDelta="0%"
android:toYDelta="70%"
android:duration="3000">
</translate>

其中黑色线条框住的是View的原始位置,黄色框住的是View动画开始时的位置,紫色线条则是整个View的70%的占比,最后集中到的点就是View要移动到的最终的位置也就是结束点。

image

Set(集合动画)

如何理解Set(集合动画),其实很简单,比如现在有一个需求,我们既要旋转又要有渐渐出现的效果,那么就要使用set了,说白了就是将多个动画组合起来。只要把上边几个都学会了,使用这个set简直so easy。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"
></alpha>
<rotate
android:pivotX="50%"
android:pivotY="50%"
android:fromDegrees="0"
android:toDegrees="180"
></rotate>
</set>

image

动态创建动画

上边所展示的都是通过xml文件写的动画,都是静态写好了的。那么想要动态的创建动画对象又该如何?其实很简单,通过代码的方式创建动画它们的名称和使用xml文件创建时名称都是对应的,提供的构造函数也都是必备的参数值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 //创建Alpha动画
var alpha = AlphaAnimation(0.0F, 1.0F)
alpha.duration = 3000
this.txtAnimation.startAnimation(alpha)
//创建Rotate动画
var rotate = RotateAnimation(0F, 360F, Animation.RELATIVE_TO_SELF, 50F, Animation.RELATIVE_TO_SELF, 50F)
//创建Scale动画
var scale = ScaleAnimation(0F, 1F, 0F, 1F, Animation.RELATIVE_TO_SELF, 50F, Animation.RELATIVE_TO_SELF, 50F)
//创建translate动画
var translate = TranslateAnimation(
Animation.RELATIVE_TO_SELF,
10F,
Animation.RELATIVE_TO_SELF,
80F,
Animation.RELATIVE_TO_SELF,
0F,
Animation.RELATIVE_TO_SELF,
70F
)
//创建Set动画
var set = AnimationSet(this, null)
set.duration = 3000
set.addAnimation(alpha)
set.addAnimation(rotate)

从Animation继承的属性

以上所有的动画对象都是从Animation类继承来的,所有有一些公共的属性也会继承过来。

属性 说明
android:duration 动画持续时间,以毫秒为单位
android:fillAfter 如果设置为true,控件动画结束时,将保持动画最后时的状态
android:fillBefore 如果设置为true,控件动画结束时,还原到开始动画前的状态
android:fillEnabled 与android:fillBefore 效果相同,都是在动画结束时,将控件还原到初始化状态
android:repeatCount 重复次数
android:repeatMode 重复类型,有reverse和restart两个值,reverse表示倒序回放,restart表示重新放一遍,必须与repeatCount一起使用才能看到效果。因为这里的意义是重复的类型,即回放时的动作。
android:interpolator 设定插值器。

动画的播放

1
2
3
4
5
//加载动画
this.btnOpenAnimation.setOnClickListener {
var animation = AnimationUtils.loadAnimation(this, R.anim.translate_anim)
this.txtAnimation.startAnimation(animation)
}

Tween Animation(逐帧动画)

这个是Drawable形式的动画,存放在drawable文件夹中,使用animation-list节点来表示。图片素材是提前准备好的。自己动手尝试下马上就会理解了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:duration="100" android:drawable="@drawable/a001"></item>
<item android:duration="100" android:drawable="@drawable/a002"></item>
<item android:duration="100" android:drawable="@drawable/a003"></item>
<item android:duration="100" android:drawable="@drawable/a004"></item>
<item android:duration="100" android:drawable="@drawable/a005"></item>
<item android:duration="100" android:drawable="@drawable/a006"></item>
<item android:duration="100" android:drawable="@drawable/a007"></item>
<item android:duration="100" android:drawable="@drawable/a008"></item>
<item android:duration="100" android:drawable="@drawable/a009"></item>
<item android:duration="100" android:drawable="@drawable/a010"></item>
<item android:duration="100" android:drawable="@drawable/a011"></item>
<item android:duration="100" android:drawable="@drawable/a012"></item>
<item android:duration="100" android:drawable="@drawable/a013"></item>
<item android:duration="100" android:drawable="@drawable/a014"></item>
<item android:duration="100" android:drawable="@drawable/a015"></item>
<item android:duration="100" android:drawable="@drawable/a016"></item>
<item android:duration="100" android:drawable="@drawable/a017"></item>
<item android:duration="100" android:drawable="@drawable/a018"></item>
</animation-list>

这里我们给一个TextView设置了background属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button android:layout_width="match_parent" android:layout_height="wrap_content"
android:text="播放动画"
android:id="@+id/btnOpenAnimation"
/>
<TextView android:layout_width="300dp" android:layout_height="300dp"
android:layout_centerInParent="true"
android:id="@+id/txtAnimation"
android:background="@drawable/anim_refresh"
android:layout_gravity="center"
/>
</RelativeLayout>

具体调用

1
2
var animationDrawable = this.txtAnimation.background as AnimationDrawable
animationDrawable.start()

显示效果
image