在一个App中,良好的交互体验无疑是很重要的一部分,而动画正是在交互之中起到了重要的作用。在Android中的动画,第一种是View Animation,也就是视图动画。第二种是Property Animation,即属性动画,还有SVG动画。而Property Animation是Google在Android3.0之后才推出的。在这之前View Animation是用的最多的。而在推出功能更加强大的Property Animation之后,View Animation用的就不再那么多了。View Animation最大的不足就是不具有交互性,虽然有视觉上的动画效果。但是假如我们让一个Button做平移操作,之后这个Button的点击事件的位置还是在原来的位置上,这就造成了不能用View Animation实现有交互性的操作。而Property Animation则是弥补了这一缺陷。
View Animation
View Animation的用法比较简单,大概有以下几种动画类型。
透明度动画
就是改变View的透明度的一种动画。
|
|
透明度有0到1,即由透明到不透明。
就这样就简单的实现了一个透明度动画,当然你还可以使用setFillAfter(动画结束后是否保留当前的动画状态)、setInterpolator()(设置插值器)、setRepeatMode()(设置重复模式,有restart和reverse两种值可选)、setRepeatCount()(设置重复次数)等来增加动画效果。其他的可以自己去查。
旋转动画
|
|
从0度开始旋转360度,并且以(100,100)为旋转中心。
当然,这里也可以设置旋转参考系为自身或者父布局:
|
|
这里以自身为参考,并且指定为0.5,即围绕自己的中心点旋转,由0到360度。
位移动画
|
|
由(0,200)移动到(0,300)。
#### 缩放动画
|
|
开始横向的缩放因子为0,结束的缩放因子为2。开始的竖向缩放因子为0,结束的缩放因子为2。即从没有,到横向竖向分别扩大两倍。
|
|
和上面一样,以自身中心点为参考点缩放。即从没有,到横向竖向分别扩大一倍。
以上就是View Animation所支持的四种动画类型,当然这四种类型是可以一起使用的。这就要借助于AnimationSet了。
|
|
利用addAnimation()将动画添加进来。最后startAnimation()就开始执行整个动画集合了。
View Animation也是可以进行动画的监听的:
|
|
这样就可以在动画运行时进行进行相应的逻辑处理了。
在xml中使用
View Animation也是支持在xml文件中实现的,这样写的一个好处是复用性好。当遇到一样的动画时直接引用就好了。
首先,需要在res文件夹下新建anim文件夹,在这里面新建一个xml就可以使用View Animation了。
透明度动画:
|
|
fromAlpha:开始透明度
toAlpha:结束透明度
旋转动画:
|
|
fromDegrees:开始旋转的角度
toDegrees:结束旋转的角度
pivotX:旋转点X坐标
pivotY:旋转点Y坐标
这里需要注意一下PivotX和PivotY的值,当你写成 50时是相对于父布局参考而言的,而当你写成50%时表示的是相对于自身参考而言的。
官方文档有提到,具体看这里:
(“50” for 50% relative to the parent, or “50%” for 50% relative to itself)
平移动画:
|
|
fromXDelta:开始X坐标
fromYDelta:开始Y坐标
toXDelta:结束X坐标
toYDelta:结束Y坐标
缩放动画:
|
|
fromXScale:开始X坐标缩放因子
toXScale:结束X坐标缩放因子
fromYScale:开始Y坐标缩放因子
toYScale:结束Y坐标缩放因子
pivotX:缩放中心X坐标
pivotY:缩放中心Y坐标
动画集合:
|
|
在xml中使用和在代码中使用相差不大,基本属性都一致。
Property Animation
接下来轮到Property Animation了,这一动画时真的可以改变View的属性值,用它可以实现几乎所有的动画效果。
ValueAnimator
ValueAnimator是整个属性动画机制当中最核心的一个类,属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。
ValueAnimator使用非常简单:
|
|
首先利用ValueAnimator的ofFloat()静态方法得到ValueAnimator对象,之后传入0和1,表示让ValueAnimator计算由0平滑过渡到1,然后设置了时长为1s。最后,调用start()方法,开启动画。但是,这时你是看不到任何动画效果的。因为ValueAnimator只是不断的计算值,所以可以用到监听器来获得每一次的值:
|
|
通过addUpdateListener()方法,注册监听器,当动画执行时就会不断的回调该方法。在该方法内部,就可以通过getAnimatedValue()得到每一次计算出的值,利用该数值我们就可以设置给View,从而看到动画效果。下面是得到的每一次的值。
the value is 0.0
the value is 0.00252449
the value is 0.01070955
the value is 0.02447176
the value is 0.04365423
the value is 0.06803828
the value is 0.09549156
the value is 0.12912908
the value is 0.16699407
the value is 0.20865482
the value is 0.25090742
the value is 0.29854682
the value is 0.3484823
the value is 0.400145
the value is 0.4529459
the value is 0.5031415
the value is 0.5564282
the value is 0.6090715
the value is 0.6604718
the value is 0.70718765
the value is 0.7545208
the value is 0.79895246
the value is 0.83997655
the value is 0.87712574
the value is 0.9081696
the value is 0.93663126
the value is 0.9601159
the value is 0.978356
the value is 0.9905453
the value is 0.9980668
the value is 1.0
ofFloat(float…values)是可以传入多个值的,比如:
|
|
这样就表示一个值由0到3再到5再到1,这样是可以完成复杂的逻辑效果的。
当然ValueAnimator中还提供了ofInt(),ofArgb()方法。使用上与ofFloat()无差异。只是后两个方法显得更高级一些,ofArgb()是可以对我们给出的颜色进行平滑过渡的,其实内部实现是TypeEvaluator,后面会说到它的作用。
这里需要注意的是,addUpdateListener()方法中getAnimatedValue()返回的是一个Object对象,我们需要转换为我们想要的类型。当你使用ofFloat()时,这里就转换为float类型。而当你使用的是ofInt()方法时,这里也就应该转换为int类型。如果你使用的是ofFloat(),却转换为int,是会报出类型转换异常的。
ValueAnimator中还由其他方法,如:setRepeatCount(),设置重复次数、setRepeatMode(),设置重复模式,有restart(重新开始动画)和reverse(逆向执行动画)可选、cancel()取消动画。其余的方法可以自己查看官方文档。
ObjectAnimator
其实ObjectAnimator是继承自ValueAnimator的:
所以,在ValueAnimator中的方法ObjectAnimator也是可以使用的。只不过ObjectAnimator在ValueAnimator的基础上又实现了动画的效果,这是ValueAnimator中没有的。它是可以直接对任意对象的任意属性进行动画操作的,比如说View的alpha、translate等属性。
|
|
是不是和上面的View Animation的AlphaAnimation及其相似呢?第一个参数表示那个View执行动画,第二个参数要改变的属性,第三个参数是一个可变值,可以有多个值。0表示完全透明,1表示完全不透明。
|
|
这样就可以实现在竖直方向上的平移效果,最后View会停在500位置,你可以加一个点击事件。会发现,ObjectAnimator是真的会改变动画的属性,不再是View Animation那样,移动后点击事件还在原位置。
所有可以支持的属性如下,基本上和View Animation中的属性很像:
- translationX and translationY: These properties control where the View is located as a delta from its left and top coordinates which are set by its layout container.
- rotation, rotationX, and rotationY: These properties control the rotation in 2D (rotation property) and 3D around the pivot point.
- scaleX and scaleY: These properties control the 2D scaling of a View around its pivot point.
- pivotX and pivotY: These properties control the location of the pivot point, around which the rotation and scaling transforms occur. By default, the pivot point is located at the center of the object.
- x and y: These are simple utility properties to describe the final location of the View in its container, as a sum of the left and top values and translationX and translationY values.
- alpha: Represents the alpha transparency on the View. This value is 1 (opaque) by default, with a value of 0 representing full transparency (not visible).
那么这些属性来自于哪里呢?其实ObjectAnimator内部的工作机制并不是直接对我们传入的属性名进行操作的,而是会去寻找这个属性名对应的get和set方法,因此alpha属性所对应的get和set方法应该就是:
|
|
在View中是可以找到这两个方法的,也就是任何继承自View的对象都可以使用上面的属性。
The object property that you are animating must have a setter function (in camel case) in the form of set
(). Because the ObjectAnimator automatically updates the property during animation, it must be able to access the property with this setter method. For example, if the property name is foo, you need to have a setFoo()
method. If this setter method does not exist, you have three options:
- Add the setter method to the class if you have the rights to do so.
- Use a wrapper class that you have rights to change and have that wrapper receive the value with a valid setter method and forward it to the original object.
- Use ValueAnimator instead.
官方文档中也有说明,大意就是你想操纵的View必须要有setXXXX()方法(XXXX为属性名称)。ObjectAnimator是在动画执行过程中直接更改属性的,从而完成动画效果。如果,setter方法不存在,给出了三点解决办法。
- 添加setter方法。
2.使用包装类的方法给一个属性增加getter、setter方法。
|
|
使用:
3.使用ValueAnimator代替。
注意:getter属性是非必须的,那么什么时候一定会用到getter属性呢。因为ofFloat()和ofInt()方法中都有一个可变参数,我们可以传入多个参数。也就是说只传入一个参数也是可以的,这时候这一个参数只表示结束值。那从哪个值开始呢?这里就用到了getter方法,getter方法中返回的值会默认设为开始的数值,假如我们只传入一个参数的情况下。
来看系统的View源码中Alpha值实现:
|
|
也就是getter中alpha默认值是0。所以,当我们这样时:
|
|
是会看到view先完全透明(0),最后停在半透明状态的(0.5)。
也就是当且仅当动画的只有一个过渡值时,系统才会调用对应属性的getter函数来得到动画的初始值。但是,setter方法是属性必须要有的。
组合动画
和View Animation一样,Propty Animation也是支持组合动画的。想使用组合动画,首先要使用AnimatorSet。
|
|
playTogether()表示动画一起执行,playSequentially()表示动画一个接一个执行。
AnimatorSet中还提供了一个play()方法,会返回一个AnimatorSet.Builder。AnimatorSet.Builder中有四个方法,用于组合动画到一起。
- after(long delay):延时指定毫秒执行动画
- after(Animator anim) 将现有动画插入到传入的动画之后执行
- before(Animator anim) 将现有动画插入到传入的动画之前执行
- with(Animator anim) 将现有动画和传入的动画同时执行
Animator监听器
前面ValueAnimator的一个重要的监听器是addUpdateListener(),可以在其中getAnimatedValue()得到当前animation的值。
addUpdateListener()只是Animator监听器中的一个,Animator还有两个监听器用于控制动画执行的开始到结束的每一个过程。
|
|
看名字就能猜出这几个方法会回调的时间了。但是有时候,我们只想监听一个或者几个事件,所以这里还提供了AnimatorListenerAdapter()用于监听任意一个事件。
|
|
这里就只是监听了动画结束这一事件。
在xml中使用
Property Animation也是可以在xml中使用的,以此来提高复用率。
首先需要在res下新建animator文件夹。在其中新建xml文件就可以使用Property Animation了。
在其中可以使用三种标签:
animator : 对应代码中的ValueAnimator
objectAnimator : 对应代码中的ObjectAnimator
set : 对应代码中的AnimatorSet
在这三个标签内可以进行动画的组合,或者单独使用,好多属性与上面View Animation相似。想要了解更多,请看这里:
|
|
在代码中加载:
如果在xml中使用了ValueAnimator,则还是可以在代码中监听动画执行过程中返回的值,对View做相应的处理。
|
|
Ending
以上就是Android中,动画的基本使用,其中既有View Animation也有Property Animation。虽然花费了时间来整理,但还是值得的,以后再查找也好有个方便。好了,本篇就到这里。