IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Android 补间动画、帧动画和属性动画开发大全 -> 正文阅读

[游戏开发]Android 补间动画、帧动画和属性动画开发大全

一、前言

为了使用户的交互更加流畅自然,动画也就成为了一个应用中必不可少的元素之一。在 Android 中常用的动画分类无外乎三种,最早的 帧动画 、补间动画 以及 3.0 之后加入的 属性动画,是它们组成了 Android 中各种炫酷亮眼的动画效果。这里是官方的动画相关开发文档链接

二、动画

2.1 动画分类

Android中有三种动画,分别是补间动画(Tween Animation),帧动画(Frame Animation)和属性动画(Property Animation)。

2.2 补间动画

这类动画比较简单,一般就是平移、缩放、旋转、透明度,或者其组合,可以用代码或者xml文件的形式。
四个动画效果实现类:TranslateAnimation、ScaleAnimation、RotateAnimation、AlphaAnimation、组合动画实现类:AnimationSet,对应的的XML标签为translate、 scale、 rotate、alpha、set,其中set里还可以放set,然后放在放置在res/anim/目录下。

2.2.1 平移(TranslateAnimation)

共有属性:
duration表示这一次动画持续的时间
fillAfter表示动画结束时,是否保持最后一帧的样子
fillBefore表示动画结束时,是否保持第一帧的样子
repeatCount表示动画循环的次数,默认为 0 次不循环,-1 为无限循环。
repeatMode表示是循环的模式,reverse 是从一次动画结束开始,restart 是从动画的开始处循环
interpolator是一个插值器资源,它可以控制动画的播放速度
shareInterpolator表示是否与 set 中其他动画共享插值器,false为各自使用各自的插值器

平移动画属性:
fromXDelta
fromYDelta
起始时,X/Y 方向的位置
toXDelta
toYDelta
终止时,X/Y 方向的位置
这四个属性都支持同样的单位,是三种表达方式,浮点数、num% 和 num%p

  • 浮点数 位置为 View 的左边距/上边距 + 此数值 正数为右,负数为左
  • num% 位置为 View 的左边距/上边距 + View宽的百分之num 正数为右,负数为左
  • num%p 位置为 View 的左边距/上边距 + 父容器的百分之num 正数为右,负数为左

动画效果:
在这里插入图片描述

<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromXDelta="0"
    android:fromYDelta="0"
    android:toXDelta="300"
    android:toYDelta="300"
    android:repeatCount="-1"
    android:repeatMode="reverse"/>
Animation translateAnim = AnimationUtils.loadAnimation(this, R.anim.view_translate);
view.startAnimation(translateAnim);

2.2.2 缩放(ScaleAnimation)

属性:
fromXScale
fromYScale
代表缩放时,X/Y 坐标起始大小,浮点值,0.5代表自身的一半,2.0代表自身的两倍大小。
toXScale
toYScale
代表缩放时,X/Y 缩放结束时候大小。
pivotX浮点数。在对象缩放时要保持不变的 X 坐标。
pivotY浮点数。在对象缩放时要保持不变的 Y 坐标。

动画效果:
在这里插入图片描述

<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromXScale="0.1"
    android:fromYScale="0.1"
    android:pivotX="0"
    android:pivotY="0"
    android:toXScale="1.0"
    android:toYScale="1.0"
    android:repeatCount="-1"
    android:repeatMode="reverse"/>
Animation scaleAnim = AnimationUtils.loadAnimation(this, R.anim.view_scale);
view.startAnimation(scaleAnim);

2.2.3 旋转(RotateAnimation)

属性:
fromDegrees 起始角度 单位度 浮点值
toDegrees 结尾角度 单位度 浮点值
pivotX旋转中心点的 X 坐标,这个数值有三种表达方式
pivotY旋转中心点的 Y 坐标,这个数值有三种表达方式

  • 纯数字 例如 20 ,代表相对于自身左边缘或顶边缘 + 20 像素
  • num% 代表 相对于自身左边缘或顶边缘 + 自身宽 的百分之 num
  • num%p 代表相对于自身左边缘或顶边缘 + 父容器 的百分之 num

动画效果:
在这里插入图片描述

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromDegrees="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="-1"
    android:repeatMode="reverse"
    android:toDegrees="1800" />
Animation rotateAnim = AnimationUtils.loadAnimation(this, R.anim.view_rotate);
view.startAnimation(rotateAnim);

2.2.4 透明度(AlphaAnimation)

属性:
fromAlpha表示动画开始时的透明度
toAlpha 表示动画结束时候的透明度
取值为[0.0,1.0],0代表完全透明,1代表不透明。

动画效果:
在这里插入图片描述

<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromAlpha="0"
    android:repeatCount="-1"
    android:repeatMode="reverse"
    android:toAlpha="1" />
Animation scaleAnim = AnimationUtils.loadAnimation(this, R.anim.view_scale);
view.startAnimation(scaleAnim);

2.2.5 组合(AnimationSet)

动画效果:
在这里插入图片描述

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:shareInterpolator="true"
    android:fillAfter="true"
    android:duration="15000">
    <alpha
        android:fromAlpha="0"
        android:toAlpha="1" />
    <rotate
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="720" />
    <scale
        android:fromXScale="0.1"
        android:fromYScale="0.1"
        android:pivotX="0%"
        android:pivotY="0%"
        android:toXScale="1.0"
        android:toYScale="1.0" />

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

java代码:

AnimationSet set = (AnimationSet) AnimationUtils.loadAnimation(this,R.anim.view_animation_set);
view.startAnimation(set);
//动画监听
set.setAnimationListener(new Animation.AnimationListener() {
    @Override
    public void onAnimationStart(Animation animation) {

    }

    @Override
    public void onAnimationEnd(Animation animation) {
        
    }

    @Override
    public void onAnimationRepeat(Animation animation) {

    }
});
//结束动画
//view.clearAnimation();

2.2.6 TimeInterpolator 时间插值器

TimeInterpolator的作用是根据时间流逝的百分比来计算出当前属性值改变的百分比。负责控制动画变化的速率,使得基本的动画效果能够以匀速、加速、减速、抛物线速率等各种速率变化。其实质是一个数学函数 y = f(x),定义域 x 属于 (0.0,1.0) 的 float 值,值域 y 也是 (0.0,1.0) 的 float 值,曲线的斜率是速度。插值器就是策略模式的一个应用。

(1)系统内置插值器:
AccelerateDecelerateInterpolator
使用:@android:anim/accelerate_decelerate_interpolator 其变化开始和结束速率较慢,中间加速
AccelerateInterpolator
使用: @android:anim/accelerate_interpolator 其变化开始速率较慢,后面加速
DecelerateInterpolator
使用:@android:anim/decelerate_interpolator 其变化开始速率较快,后面减速
LinearInterpolator
使用:@android:anim/linear_interpolator 其变化速率恒定
AnticipateInterpolator
使用:@android:anim/anticipate_interpolator 其变化开始向后甩,然后向前
AnticipateOvershootInterpolator
使用:@android:anim/anticipate_overshoot_interpolator 其变化开始向后甩,然后向前甩,过冲到目标值,最后又回到了终值
OvershootInterpolator
使用:@android:anim/overshoot_interpolator 其变化开始向前甩,过冲到目标值,最后又回到了终值
BounceInterpolator
使用:@android:anim/bounce_interpolator 其变化在结束时反弹
CycleInterpolator
使用:@android:anim/cycle_interpolator 循环播放,其速率为正弦曲线
(2)自定义插值器
这里有一个网站可以模拟我们需要的插值器。点击链接,选择scaling,library选
择spring。如下图下面就是一个回弹的插值器。
在这里插入图片描述
factor = 0.2
pow(2, -10 * x) * sin((x - factor / 4) * (2 * PI) / factor) + 1
代码实现上面的插值器,需要继承Interpolator实现getInterpolation()方法。如下:

public class SpringScaleInterpolator implements Interpolator {
    private float factor;//回弹因子,值越大效果越慢
    public SpringScaleInterpolator(float factor) {
        this.factor = factor;
    }
    @Override
    public float getInterpolation(float input) {
        return (float) (Math.pow(2, -10 * input) * Math.sin((input - factor / 4) * (2 * Math.PI) / factor) + 1);
    }
}

顺便提一下其他实现这种弹性动画的库:
1、Facebook推出的rebound库,这里是github链接
2、谷歌官方的SpringAnimation,这里是官网地址。下面是一个官方文档上的效果展示。
在这里插入图片描述要使用基于物理特性的支持库:

dependencies {
      def dynamicanimation_version = "1.0.0"
      implementation 'androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version'
}

说到这个库顺便说一下FlingAnimation投掷动画,投掷动画利用与对象速度成正比的摩擦力。您可以使用该动画为某个对象的某个属性添加动画效果,还可以使用该动画逐渐结束动画。该动画具有一个初始动量,主要从手势速度获得,然后逐渐变慢。 当动画速度足够低,在设备屏幕上没有任何可见变化时,动画便会结束。
在这里插入图片描述

2.3 帧动画

简单讲就是把几个静态的图片快速播放形成动画,可以使用AnimationDrawable,官方推荐使用XML文件,放在res/drawable/路径下

2.3.1 实现

在这里插入图片描述
在这里插入图片描述
xml中实现:

<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
    <item android:drawable="@drawable/run_0" android:duration="100"/>
    <item android:drawable="@drawable/run_1" android:duration="100"/>
    <item android:drawable="@drawable/run_2" android:duration="100"/>
    <item android:drawable="@drawable/run_3" android:duration="100"/>
    <item android:drawable="@drawable/run_4" android:duration="100"/>
    <item android:drawable="@drawable/run_5" android:duration="100"/>
</animation-list>

oneshot属性,用于设置是否需要循环播放,true为仅播放一次,false 为连续的循环播放。

AnimationDrawable animationDrawable = (AnimationDrawable) getResources().getDrawable(R.drawable.view_frame_anim);
imageView.setBackground(animationDrawable);
animationDrawable.start();

特别注意:
AnimationDrawable 调用的 start()方法不能在 Activity 的 onCreate() 方法期间调用,因为
AnimationDrawable 尚未完全附加到窗口。如果您想立即播放动画而无需互动,那么需要从Activity 中的 onStart() 方法进行调用。

2.3.2 优化

由于需要多张图片,apk的体积会比较大,内存开销也会比较大。目前我认为比较好的方案:
1、将图片资源适当压缩,放到sd卡,预值或者网络下载,这样可以有效减小apk体积。
2、动画实现方式上不使用原生的方式,可以通过opengl去渲染。
3、可以通过播放视频的方式代替多张图片实现动画,视频文件可以压缩到很小。第三方视频动画框架:腾讯VAP(Video Animation Player)字节AlphaPlayer

2.4 属性动画

需要属性动画的原因:是因为前面两种动画存在一些缺点,1、作用对象有限:只能够作用在View上
为了弥补视图动画的缺陷,于是Android在3.0(API 11)开始提供了一种全新的动画模式:属性动画(Property Animation)。属性动画,顾名思义,只要对象里有属性的set和get方法,就可以利用这个属性去做动画。

  1. 两个使用方法类:ValueAnimator 类 和 ObjectAnimator
  2. 两个辅助使用类:插值器 & 估值器
    属性动画支持使用 XML 声明属性动画,也可以以代码方式实现。属性动画的 XML 文件保存到
    res/animator/ 目录中。对应标签:
  • ValueAnimator - <animator>
  • ObjectAnimator - <objectAnimator>
  • AnimatorSet - <set>

部分常用属性:
android:valueTo浮点数、整数或颜色。必需。动画的结束值。
android:valueFrom浮点数、整数或颜色。必需。动画的开始值。
android:duration整数。动画的时间,以毫秒为单位。默认为 300ms。
android:startOffset整数。调用 start() 后动画延迟的毫秒数。。
android:repeatCount整数。动画的重复次数。设为 “-1” 表示无限次重复,也可设为正整数。例如,值 “1” 表示动画在初次播放后重复播放一次,因此动画总共播放两次。默认值为 “0”,表示不重复。
android:repeatMode整数。动画播放到结尾处的行为。
android:repeatCount 必须设置为正整数或 “-1”,该属性才有效。设置为 “reverse” 可让动画在每次迭代时反向播放,设置为 “repeat” 则可让动画每次从头开始循环播放。
android:valueType关键字。intType动画值为整数,floatType(默认)动画值为浮点数
android:propertyName字符串。必需。要添加动画的对象属性,通过其名称引用。例如,可以为 View 对象指定 “alpha” 或 “backgroundColor”。

xml示例:

<set android:ordering="sequentially">//依序播放此集合中的动画
        <set>
            <objectAnimator
                android:propertyName="x"
                android:duration="500"
                android:valueTo="400"
                android:valueType="intType"/>
            <objectAnimator
                android:propertyName="y"
                android:duration="500"
                android:valueTo="300"
                android:valueType="intType"/>
        </set>
        <objectAnimator
            android:propertyName="alpha"
            android:duration="500"
            android:valueTo="1f"/>
    </set>

代码中使用:

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(context,
        R.animator.property_animator);
set.setTarget(Object);
set.start();

2.4.1 ValueAnimator

通过不断控制值的变化,再不断手动赋给对象的属性,从而实现动画效果。
ValueAnimator类中有3个重要方法:

ValueAnimator.ofInt(int values)
ValueAnimator.ofFloat(float values)
ValueAnimator.ofObject(int values)

用代码实现,以及动画监听:

ValueAnimator anim = ValueAnimator.ofInt(btn.getLayoutParams().width, 900);
// 初始值 = 当前按钮的宽度  结束值 = 900
// 允许传入一个或多个Int参数 
// 1. 输入一个的情况(如a):从0过渡到a; 
// 2. 输入多个的情况(如a,b,c):先从a平滑过渡到b,再从b平滑过渡到C
anim.setDuration(3000);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        // 获得改变后的值
        int currentValue = (int) animation.getAnimatedValue();
        // 将改变后的值赋给对象的属性值
        btn.getLayoutParams().width = currentValue;
        // 刷新视图,重新绘制
        btn.requestLayout();
    }
});

btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        anim.start();
    }
});
//anim.cancel();

动画效果如下:

在这里插入图片描述
动画监听,需要重写四个方法,通过监听动画开始 / 结束 / 重复 / 取消时刻来进行一系列操作.

anim.addListener(new Animator.AnimatorListener() {
    @Override
    public void onAnimationStart(Animator animation) {

    }

    @Override
    public void onAnimationEnd(Animator animation) {

    }

    @Override
    public void onAnimationCancel(Animator animation) {

    }

    @Override
    public void onAnimationRepeat(Animator animation) {

    }
});

在这里插入图片描述
AnimatorSet类、ValueAnimator、ObjectAnimator都可以使用addListener()监听器。有些时候我们并不需要监听动画的所有时刻,上面监听器是必须重写4个方法,所以可以采用动画适配器
AnimatorListenerAdapter 监听。
在这里插入图片描述

anim.addListener(new AnimatorListenerAdapter() {  
// 向addListener()方法中传入适配器对象AnimatorListenerAdapter()
// 由于AnimatorListenerAdapter中已经实现好每个接口
// 所以这里不实现全部方法也不会报错
    @Override  
    public void onAnimationStart(Animator animation) {  
    // 如想只想监听动画开始时刻,就只需要单独重写该方法就可以
    }  
});

ValueAnimator.ofInt()与ValueAnimator.oFloat()仅仅只是在估值器上的区别:

  • ValueAnimator.oFloat()采用默认的浮点型估值器 (FloatEvaluator)
  • ValueAnimator.ofInt()采用默认的整型估值器(IntEvaluator)
    插值器(Interpolator)决定动画的变化速度(匀速、加速)
    估值器(TypeEvaluator)决定属性值的在动画不同完成程度的值
    那么如何从初始值过渡到结束值呢?
    其实是系统内置了一个 FloatEvaluator估值器,内部实现了初始值与结束值以浮点型的过渡逻辑.
    下边看一下具体实现:
//实现了TypeEvaluator接口
public class FloatEvaluator implements TypeEvaluator {  

    //重写evaluate()方法
    public Object evaluate(float fraction, Object startValue, Object endValue) { 
        // 用结束值减去初始值,算出它们之间的差值
        // 用上述差值乘以fraction系数
        //fraction:表示动画完成度(根据它来计算当前动画的值),也是插值器getInterpolation()的返回值
        // 再加上初始值,就得到当前动画的值
        float startFloat = ((Number) startValue).floatValue();  
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);  
    }  
} 

ValueAnimator.ofObject()的本质还是操作值,只是采用将值封装到一个对象里的方式对值操作。下边自定义估值器会介绍。

2.4.2 ObjectAnimator

ObjectAnimator animator = ObjectAnimator.ofInt(Object target, String propertyName, int… values)
ObjectAnimator animator = ObjectAnimator.ofFloat(Object object, String property, float …values);
ObjectAnimator animator = ObjectAnimator.ofObject(Object target, String propertyName,
TypeEvaluator evaluator, Object… values)
// Object object:需要操作的对象
// String property:需要操作的对象的属性
// float …values:动画初始值 & 结束值(不固定长度)
//TypeEvaluator evaluator 估值器
// 若是两个参数a,b,则动画效果则是从属性的a值到b值
// 若是三个参数a,b,c,则则动画效果则是从属性的a值到b值再到c值
// 至于如何从初始值 过渡到 结束值,同样是由估值器决定,此处ObjectAnimator.ofFloat()是有系统内置的浮点型估值器FloatEvaluator
anim.setDuration(500);// 设置动画运行的时长
anim.setStartDelay(500);// 设置动画延迟播放时间
anim.setRepeatCount(0);// 设置动画重复播放次数 = 重放次数+1;动画播放次数 = infinite时,动画无限重复
anim.setRepeatMode(ValueAnimator.RESTART);// 设置重复播放动画模式
// ValueAnimator.RESTART(默认):正序重放
// ValueAnimator.REVERSE:倒序回放

2.4.2.1 平移

动画效果:
在这里插入图片描述
java代码实现:

float translationX = btn.getTranslationX();
ObjectAnimator animator = ObjectAnimator.ofFloat(btn, View.TRANSLATION_X, translationX, 300, translationX);
animator.setDuration(5000);
animator.start();

2.4.2.2 缩放

动画效果:
在这里插入图片描述
java代码:

ObjectAnimator animator = ObjectAnimator.ofFloat(btn, View.SCALE_X, 1f, 0.5f, 1f);
animator.setDuration(5000);
animator.start();

2.4.2.3 旋转

动画效果:
在这里插入图片描述
java代码:

ObjectAnimator animator = ObjectAnimator.ofFloat(btn, View.ROTATION, 0f, 360f);
animator.setDuration(5000);
animator.start();

2.4.2.4 透明度

动画效果:

在这里插入图片描述
java代码:

ObjectAnimator animator = ObjectAnimator.ofFloat(btn, View.ALPHA, 0f, 0.5f, 1f, 0f);
animator.setDuration(5000);
animator.start();

2.4.2.5 组合动画

AnimatorSet.play(Animator anim) :播放当前动画
AnimatorSet.after(long delay) :将现有动画延迟x毫秒后执行
AnimatorSet.with(Animator anim) :将现有动画和传入的动画同时执行
AnimatorSet.after(Animator anim) :将现有动画插入到传入的动画之后执行
AnimatorSet.before(Animator anim) : 将现有动画插入到传入的动画之前执行
AnimatorSet.playTogether(Animator... items) :几个动画同时播放

动画效果:
在这里插入图片描述
java代码:

AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(animatorTranslation, animatorAlpha, animatorScale, animatorRotation);
animatorSet.start();

2.4.3 ViewPropertyAnimator

属性动画的一种简写方式:
ViewPropertyAnimator 有助于使用单个底层 Animator 对象轻松为 View 的多个属性并行添加动画效果。它的行为方式与 ObjectAnimator 非常相似,因为它会修改视图属性的实际值,但在同时为多个属性添加动画效果时,它更为高效。此外,使用 ViewPropertyAnimator 的代码更加简洁,也更易读。
View.animate().xxx().xxx();
// 调用animate()方法返回值是一个ViewPropertyAnimator对象,之后的调用的所有方法都是通过该实例完成。
// 调用该实例的各种方法来实现动画效果。
// ViewPropertyAnimator所有接口方法都使用连缀语法来设计,每个方法的返回值都是它自身的实例
// 因此调用完一个方法后可直接连缀调用另一方法,即可通过一行代码就完成所有动画效果。

多个ObjectAnimator对象

ObjectAnimator animX = ObjectAnimator.ofFloat(view, "translationX", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(view, "translationY", 50f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();

单个ObjectAnimator对象

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("translationX", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("translationY", 50f);
ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY).start();

ViewPropertyAnimator

view.animate(). translationX(50f).translationY(50f);

2.4.4 Keyframe

如果要控制动画速率的变化,我们可以通过自定义插值器,也可以通过自定义估值器来实现。
为了解决方便的控制动画速率的问题,谷歌定义了一个Keyframe的类,Keyframe直译过来就是关键帧,意思就是我们只需要定义关键的帧,中间的部分系统会自动补上。
使用keyframe分三步:

第一步:生成Keyframe对象。
第二步:利用PropertyValuesHolder.ofKeyframe()生成PropertyValuesHolder对象。
第三步:ObjectAnimator.ofPropertyValuesHolder()生成对应的Animator对象。

关键帧的写法,这里用前面的平移动画举例:
在这里插入图片描述
代码实现:

//public static Keyframe ofFloat(float fraction, float value)

Keyframe kf0 = Keyframe.ofFloat(0, translationX); //动画进度0%时的值
Keyframe kf1 = Keyframe.ofFloat(0.5f, 300);
//kf0到kf1之间的插值器
kf1.setInterpolator(new LinearInterpolator());
Keyframe kf2 = Keyframe.ofFloat(1f, translationX); //动画进度100%时的值
//kf1到kf2之间的插值器
kf2.setInterpolator(new BounceInterpolator());
PropertyValuesHolder propertyValuesHolder = PropertyValuesHolder.ofKeyframe(View.TRANSLATION_X, kf0, kf1, kf2);
ObjectAnimator animatorTranslation = ObjectAnimator.ofPropertyValuesHolder(btn, propertyValuesHolder);
animatorTranslation.setDuration(5000);
animatorTranslation.start();

Keyframe可以定义自己的Interpolator,用来定义从上一个Keyframe到下一个Keyframe之间的动画变化规则,有了关键帧后,我们可以把一个大动画拆分成多个小动画,每个小动画可以定义自己的变化规则。
通过ObjectAnimator.ofFloat,ObjectAnimator.ofInt,ObjectAnimator.ofObject构造的属性动画,内部都会为其创建一个对应的PropertyValuesHolder,PropertyValuesHolder类是属性动画属性值的一个处理类,因为只有一个PropertyValuesHolder所以构造的属性动画只能改变一个属性值,如果你想在一个属性动画里同时改变多个属性值,那么就需要用ObjectAnimator.ofPropertyValuesHolder来构造属性动画,通过参数传入多PropertyValuesHolder。
直接跟Keyframe产生关系的是PropertyValuesHolder,而且一个PropertyValuesHolder会对应一个Keyframe集合,因为一个动画至少存在两个状态,开始状态和结束状态,所以至少会有两个Keyframe,当然我们也可以通过增加Keyframe来描述中间的状态。
为了描述PropertyValuesHolder和Keyframe一对多的关系,Android提供了KeyframeSet类来管理多个Keyframe,每个KeyframeSet都会实现Keyframes的接口,PropertyValuesHolder直接依赖于Keyframes。关系图如下:

在这里插入图片描述

2.4.5 自定义估值器

自定义估值器,先看效果:

在这里插入图片描述
估值器代码实现:

public class CharEvaluator implements TypeEvaluator<Character> {
    @Override
    public Character evaluate(float fraction, Character startValue, Character endValue) {
    //在ASCII码表中,每个字符都是有数字跟他一一对应的,字母A到字母Z之间的所有字母对应的数字区间为65到90;在程序中,我们能通过数字强转成对应的字符,也可以通过字符转成数字。
        int startInt  = (int)startValue;
        int endInt = (int)endValue;
        int curInt = (int)(startInt + fraction *(endInt - startInt));
        char result = (char)curInt;
        return result;
    }
}

动画代码实现:

ObjectAnimator colorAnimator = ObjectAnimator.ofInt(btn, "BackgroundColor", 0xffffffff, 0xffff00ff, 0xffffff00, 0xffffffff);
ObjectAnimator animator = ObjectAnimator.ofObject(btn, "CharText", new CharEvaluator(), new Character('A'), new Character('Z'));
AnimatorSet set = new AnimatorSet();
set.play(colorAnimator).with(animator);
set.setDuration(3000);
set.start();

自定义的按钮,增加CharText属性。

public class CharButton extends Button {
    public CharButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public void setCharText(Character character) {
        setText(String.valueOf(character));
    }
}

三、动画原理分析

3.1 属性动画原理

(1) 动画是由许多的关键帧组成的,这是一个动画能够动起来的最基本的原理。
(2) 属性动画的主要组成是 PropertyValuesHolder,而 PropertyValuesHolder 又封装了关键帧。
(3) 动画开始后,其监听了 Choreographer 的 vsync,使得其可以不断地调用 doAnimationFrame() 来驱动动画执行每一个关键帧。
(4) 每一次的 doAnimationFrame() 调用都会去计算时间插值,而通过时间插值器计算得到 fraction 又会传给估值器,使得估值器可以计算出属性的当前值。
(5) 最后再通过 PropertyValuesHolder 所记录下的 Setter 方法,以反射的方式来修改目标属性的值。当属性值一帧一帧的改变后,形成连续后,便是我们所见到的动画。

3.2 属性动画与补间动画的区别

补间动画存在一些限制,它只支持对象的一部分来添加动画效果;例如,可以对视图的缩放和旋转添加动画效果,但无法对背景颜色添加动画效果。

补间动画的另一个缺点是它只会在绘制视图的位置进行修改,而不会修改实际的视图本身。例如,如果您为某个按钮添加了动画效果,使其可以在屏幕上移动,该按钮会正确绘制,但能够点击按钮的实际位置并不会更改。

属性动画在动画效果方面更丰富,例如颜色、位置或大小等。

四、动画框架

4.1 Lottie

Lottie (官网链接)(github地址)是 Airbnb开源的一套跨平台的完整的动画效果解决方案,设计师可以使用 Adobe After Effects 设计出漂亮的动画之后,使用 Lottie 提供的 Bodymovin 插件将设计好的动画导出成 JSON 格式,就可以直接运用在 iOS、Android、Web 和 React Native之上,无需其他额外操作。
在这里插入图片描述
最主要的两个类:

LottieAnimationView:继承自 AppCompatImageView,是加载 Lottie 动画的默认和最简单的方式。
LottieDrawable:继承自 Drawable,具有大多数与 LottieAnimationView 相同的 API,因此可以在任何视图上使用它。
常用属性:
lottie_fileName 设置播放动画的 json 文件名称 ,在app/src/main/assets目录下
lottie_rawRes 设置播放动画的 json 文件资源
lottie_autoPlay 设置动画是否自动播放
lottie_loop 设置动画是否循环
lottie_repeatMode 设置动画的重复模式
lottie_repeatCount 设置动画的重复次数
lottie_scale 设置动画的比例(默认为1f)
lottie_progress 设置动画的播放进度
lottie_cacheStrategy 设置动画的缓存策略(默认为weak) : CacheStrategy 可以是None、Weak 和 Strong 三种形式来让 LottieAnimationView 对加载和解析动画的使用强或弱引用的方式。弱或强表示缓存中组合的 GC 引用强度。
lottie_imageAssetsFolder 设置动画依赖的图片资源文件地址

在 res/raw 或 assets/ 中存放动画的 JSON 文件,然后就可以在 xml 中直接使用,如下:
在这里插入图片描述
下边是一个小动画,先上效果:

在这里插入图片描述
gradle中配置:

dependencies {
    implementation 'com.airbnb.android:lottie:4.1.0'
}

xml使用:

<com.airbnb.lottie.LottieAnimationView
    android:id="@+id/lottieView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:lottie_rawRes="@raw/voice_anim"
    app:lottie_autoPlay="true"
    app:lottie_loop="true"
    app:lottie_repeatMode="restart"/>

在代码中实现,用代码加载本地动画资源。

mLottieView.setAnimation(R.raw.voice_anim);
        mLottieView.setRepeatMode(LottieDrawable.RESTART);
        //mLottieView.setAnimation("find_anchor.json");//assetName
        //动画里有图片,有些图片资源使用本地的图片资源
        //mLottieView.setImageAssetsFolder("images/");//src/main/assets/images/
        mLottieView.addAnimatorListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {

            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {
                mLottieView.cancelAnimation();//取消动画
            }
        });
        mLottieView.addAnimatorUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
     @Override
     public void onAnimationUpdate(ValueAnimator animation) {
         
     }
 });
       
        mLottieView.playAnimation();//开始
        mLottieView.pauseAnimation();//暂停
        mLottieView.resumeAnimation();//继续
        mLottieView.cancelAnimation();//取消

4.2 腾讯PAG

PAG(Portable Animated Graphics)是一套完整的动画工作流。提供从AE(Adobe After Effects)导出插件,到桌面预览工具,再到各端的跨平台渲染 SDK。PAG 的目标是降低或消除动画研发成本,打通设计师创作到素材交付上线的流程,不断输出运行时可编辑的高质量动画内容。
PAG接入文档
下面是一个小动画,先上效果:
在这里插入图片描述
在这里插入图片描述
xml中的写法:

<org.libpag.PAGView
    android:id="@+id/pag"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

java代码:

PAGFile pagFile = PAGFile.Load(getAssets(),"gift_icon.pag");
//也可以加载本地sd卡的文件
mPAGView.setFile(pagFile);
//动画监听
mPAGView.addListener(new PAGView.PAGViewListener() {
    @Override
    public void onAnimationStart(PAGView pagView) {

    }

    @Override
    public void onAnimationEnd(PAGView pagView) {

    }

    @Override
    public void onAnimationCancel(PAGView pagView) {

    }

    @Override
    public void onAnimationRepeat(PAGView pagView) {
        mPAGView.stop();//停止动画
    }
});
mPAGView.setRepeatCount(-1);
mPAGView.play();

4.3 Lottie vs PAG

Lottie 最早是为了解决矢量图形类动画的问题。Lottie 库和插件是 Airbnb 于2017年前后发布的一款跨平台的动画解决方案,设计师通过 bodymovin 从 AE 中将动画导出 json 文件,开发只需将其导入资源文件夹直接引用即可。

Lottie 早期的版本不支持图片类动画,导出 json 之后会自动生成一个 img 的资源文件夹,播放 .json 文件时,需要解压资源压缩包到本地目录才能正常播放。从 bodymovin V 5.1.15 之后,Lottie 将图片转为 base 64 编码,使用字符代替图像地址,并封装在 json 里,直接播放一个 .json 文件,不用再拖着一个资源文件夹了。

PAG SDK整套方案是基于 C++ 和 OpenGL 的跨平台架构研发的,不依赖平台相关的UI框架,除了能做到跨端渲染完全一致外,还能轻松移植到各个原生平台,其中也包含服务器端的渲染能力。

在性能方面,PAG应用了游戏渲染里的大量的优化经验,设计了从中间渲染数据到局部位图的多级缓存架构,加上帧预测的技术,每帧渲染耗时平均可以做到Lottie的50%左右。

由于采用二进制格式,不存在JSON的字符串解析,解码耗时平均比Lottie文件的快12倍,相同的动画内容导出文件只有Lottie一半左右大小,同时二进制文件格式也更容易做到单文件集成图片,音频,视频等任意资源。

PAG 方案的优势:

1、文件更小

PAG是二进制文件格式,并采用了可变长编码整形以及动态按位聚合这些压缩技术,让相同动画导出的文件大小平均只有 Lottie 的一半左右(都经过zip压缩后对比)。PAG 除了对特效类动画的支持可圈可点,对矢量动画的支持也是非常优秀,甚至强于 Lottie。以一个生长动画为例,Lottie 文件 14k,而 PAG 文件只有1k。

2、解码更快

由于采用二进制格式,不存在JSON的字符串解析,解码耗时平均只有Lottie文件的7.6%,同时二进制文件格式也更容易做到单文件集成图片,音频,视频等任意资源。

3、支持更多AE特性

PAG目前支持Lottie在移动端几乎所有的功能,并且额外在文本,遮罩,滤镜方面比Lottie支持更加全面。除了矢量导出,PAG还增加了视频序列帧导出,能够支持所有的AE特性。

4、性能更好

基于 C++ 和 OpenGL 硬件加速渲染,除了能做到两端渲染完全一致外,应用了游戏渲染里的大量的优化经验,从中间渲染数据到局部位图的多级缓存架构,每帧渲染耗时平均可以做到Lottie的50%左右。

5、编辑性更高

除了运行时文本编辑和占位图替换功能外,PAG还支持图层级别的任意组合修改。为复杂的应用场景提供更加灵活的编程扩展能力。

6、支持服务端渲染

PAG支持服务端渲染能力,以C++方式接入,可以支持服务端照片转特效视频以及一键大片模板等功能,结合H5快速实现运营活动页。

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-09-03 12:16:13  更:2021-09-03 12:16:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/31 1:16:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码