这是我参与8月更文挑战的第2天,活动详情查看: 8月更文挑战
借 8 月更文挑战来督促自己,感谢掘金!
一、动画的概念以及分类
掌握动画是 Android 开发的一项基本的技能。动画在某些场景下使用得当,会得到事半功倍的效果。Android 动画从大的方向可以分为视图动画和属性动画,视图动画又可以分为补间动画和帧动画,下面先看一张图:
视图动画和属性动画的本质上的区别是 是否对对象的属性行了更改, 视图动画的移动仅仅是视觉效果的移动的,该 View 本质上是没有发生移动的。
二、视图动画
视图动画的作用对象是整个 View,比如 TextView、Button等控件,它没有办法对对象的属性进行操作,这是属性动画的功能。
(1)、补间动画
补间动画又可以分成以下几种不同的类型:
- 平移动画
- 缩放动画
- 选择动画
- 透明度动画
其实大致步骤是差不多的,下面就用平移动画来写一个例子。
- 在 res 目录下新建一个 anim 的文件夹。
- 在 anim 的文件夹下新建 translate_animation 的文件。
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"
android:fromYDelta="0"
android:repeatCount="0"
android:toXDelta="500"
android:toYDelta="500">
<!--上面是平移动画的私有属性属性,以下参数是4种动画效果的公共属性,即都有的属性-->
<!--
android:duration="3000" // 动画持续时间(ms),必须设置,动画才有效果
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:interpolator = @[package:]anim/interpolator_resource // 插值器,即影响动画的播放速度,下面会详细讲
-->
</translate>
复制代码
以平移动画为例,fromXDelta 表示在 X 的方向上从哪一个位置开始进行平移(fromXDelta 自然表示从 Y的方向),toXDelta 表示是平移到 X 的某一个位置(toYDelta 同理)。
3.通过 AnimationUtils.loadAnimation() 加载动画,使用代码如下:
val translateAnimation = AnimationUtils.loadAnimation(this, R.anim.translate_animation)
translateAnimation.duration = 3000
复制代码
-
启动动画 button1.startAnimation(translateAnimation)
-
为动画设置监听事件
translateAnimation.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation?) {
Log.d("yangchao ", "translateAnimation begin")
}
override fun onAnimationEnd(animation: Animation?) {
Log.d("yangchao ", "translateAnimation in process")
}
override fun onAnimationRepeat(animation: Animation?) {
Log.d("yangchao ", "translateAnimation end")
}
})
复制代码
效果如下:
(2)、帧动画
帧动画,顾名思义就是把一张张的图片拼接在一起,形成一个 gif 动图的形式。具体的做法如下:
- 在 Drawable 的目录下新建一个文件 frame_animation:
<?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="100" />
<item
android:drawable="@drawable/a2"
android:duration="100" />
<item
android:drawable="@drawable/a3"
android:duration="100" />
<item
android:drawable="@drawable/a4"
android:duration="100" />
</animation-list>
复制代码
- a1 – a4 是存放在 drawble 下的图片名称,oneshot 代表是否只播放一次,这里设置的false,表示动画a1 – a4 不停地循环播放。
- 接下来的代码如下:
// 为 ImageView 设置 Resource,目的是加载之前的动画 XML
imageView.setImageResource(R.drawable.frame_animation)
// 获取 ImageView 的 drawable 对象,并进行强制转化
val animationDraw = imageView.drawable as AnimationDrawable
// 启动动画
animationDraw.start()
复制代码
三、属性动画
视图动画的本质上是改变 View 视觉效果,例如使用补间动画把 Buttom 从左上角移到右下角,但是我们点击右下角是没有任何反应的。属性动画作用于任意的 Java 对象,不再局限于 View 对象。在一定的时间内不断的对值进行改变,从而实现对象在属性上的动画效果。
属性动画有两个主要的类来进行控制 ValueAnimator 和 ObjectAnimator。
1、ValueAnimator
通过控制值的变化,再不断手动赋给对象的属性,从而实现动画的效果。ValueAnimator 有三个重要的方法:
- ValueAnimator.ofInt(int valus)
- ValueAnimator.ofFloat(int valus)
- ValueAnimator.ofObject(int valus)
前面两个都内置了估值器,第三个需要我们自定义估值器,自定义估值器需要继承 TypeEvaluator 类,重写 evaluate 方法。实例代码如下:
public class PointEvaluator implements TypeEvaluator<Point> {
@Override
public Point evaluate(float fraction, Point startValue, Point endValue) {
// 新值 = 开始值 + (结束值 - 开始值)* 持续时间
float x = startValue.getX() + (endValue.getX() - startValue.getX()) * fraction;
float y = startValue.getY() + (endValue.getY() - startValue.getY()) * fraction;
// 其本质上是从新创建了了个对象
return new Point(x, y);
}
}
复制代码
(1)、插值器与估值器
- 插值器(Interpolator):决定值的变化模式(匀速,加速)
- 估值器(TypeEvaluator):决定 值 的具体变化
// 动画初始时的对象,和结束时的对象
Point startPoint = new Point(RADIUS, RADIUS);
Point endPoint = new Point(700, 1000);
ValueAnimator valueAnimator = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
valueAnimator.setDuration(3000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
curPoint = (Point) animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.start();
复制代码
2、ObjectAnimator
ObjectAnimator.ofFloat(Object object, String property, float ….values)
对于属性动画,其扩展性在于:不局限于系统限定的动画,可以自定义动画,即自定义对象的属性,并通过操作自定义的属性实现动画。
属性动画的使用主要有以下几项:
四、动画基础总结
视图动画的本质上是对 View 视图的视觉效果,属性动画该则是对对象属性进行操作。