6.Android动画

Android动画

原理:不停修改view的不同属性,刷新

动画实现方式

GIf

一般Gif或者帧动画 的性能差是由于图过多,每秒种几十帧,每一帧都是一张图。一个小动画往往需要几十张图。如果变成资源下载,资源包体积难以控制。

原生

Native 动画是属性动画或者补间动画。性能相比较gif而言性能比较好,但是有大量动画的需求时,往往生产力是不够的,一开始手动码动画,一个动画最多时写了3000多行code。
Native 动画优缺点:
开发成本高
必须发版
不能完全100%还原复杂动画,调参数比较繁
图片资源大,影响apk包大小

SVG

SVG图片格式,一种矢量图形。另一个角度来讲一张图或者一个动画,是由很多上下层级的图层构成。比如当前的简单的图,看到的是一张图,但在设计工具中是三个图层构成,有着不同的上下层级顺序。
原理:通过设置帧率,来生成一个配置文件,使得每一帧都有一个配置,每一帧都是关键帧,通过帧率去刷每一帧的画面,这个思路跟gif很像,但是通过配置使得动画过程中图片都可以得到复用。性能就提升上来了。

Lottie

完全按照设计工具的设计思路来进行还原,将动画脚本导出并解析。动画脚本非常的轻量。将所有的动画拆成多个层级,每个层级layer都有一个动画配置,播放时解析多个layer的配置,并给每个layer做相应的动画。也达到了图片可以复用。当需要解析高阶插值(二次线性方程,贝塞尔曲线方程)时,性能相对而言差一点。

Lottie使用注意
都是canvas 画布操作
lottie动画很卡顿,不流畅//硬件加速,开启之后瞬间丝滑
遮罩或者蒙版,性能将会受到影响。
如果你在一个列表中使用动画, 我们建议你配置 LottieAnimationView.setAnimation(String, CacheStrategy) 的第二个参数——缓存策略,这样动画就不必每次都反序列化。

Android中的动画

三种:补间动画、帧动画、属性动画。
补间动画是放置到res/anim/下面
帧动画是放置到res/drawable/下面,子节点为animation-list,在这里定义要显示的图片和每张图片的显示时长

上下左右浮动效果

1
2
3
4
5
6
7
8
9
10
11
12
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this, "translationY", -6.0f,6.0f,-6.0f);
objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
objectAnimator.setDuration(800);
objectAnimator.start();

animator2 = ObjectAnimator.ofFloat(ivHand2, "translationY", -20,20,-20);
animator2.setRepeatMode(ValueAnimator.RESTART);
animator2.setRepeatCount(-1);
animator2.setDuration(1000);
animator2.start();


帧动画

传统的动画方法,通过顺序的播放排列好的图片来实现,类似电影,一张张图片不断的切换,形成动画效果,要自己指定每一帧。

  • 帧动画使用xml定义
    在drawable目录下定义xml文件,子节点为animation-list,在这里定义要显示的图片和每张图片的显示时长

    1
    2
    3
    4
    5
    <animation-list xmlns:androandroid:oneshot="false">
    <item android:drawable="@drawable/g1" android:duration="200" />
    <item android:drawable="@drawable/g2" android:duration="200" />
    <item android:drawable="@drawable/g3" android:duration="200" />
    </animation-list>
  • 在屏幕上播放帧动画

    1
    2
    3
    4
    5
    6
    ImageView iv = (ImageView) findViewById(R.id.iv);
    //把动画文件设置为imageView的背景
    iv.setBackgroundResource(R.drawable.animations);
    AnimationDrawable ad = (AnimationDrawable) iv.getBackground();
    //播放动画
    ad.start();

补间动画

  1. 如果动画中的图像变换比较有规律时,例如图像的移动(TranslateAnimation)、旋转(RotateAnimation)、缩放(ScaleAnimation)、透明度渐变(AlphaAnimation),这些图像变化过程中的图像都可以根据一定的算法自动生成,我们只需要指定动画的第一帧和最后一帧图像即可,这种自动生成中间图像的动画就是补间动画。
  2. 补间动画,只是一个动画效果,组件其实还在原来的位置上,xy没有改变

属性动画

  1. 补间动画改变了View的显示效果而已,而不会真正去改变View的属性,比如说,屏幕的左上角有一个按钮,然后通过补间动画将它移动到了屏幕的右下角,现在去尝试点击这个按钮,点击事件是绝对不会触发的,因为实际上这个按钮还是停留在屏幕的左上角,只不过补间动画将这个按钮绘制到了屏幕的右下角而已。
  2. 动画的对象除了传统的View对象,还可以是Object对象,动画结束后,Object对象的属性值被实实在在的改变了。

ViewPropertyAnimator

使⽤ View.animate() 创建对象,以及使⽤ViewPropertyAnimator.translationX() 等⽅法来设置动画;
可以连续调⽤来设置多个动画;
可以⽤ setDuration() 来设置持续时间;
可以⽤ setStartDelay() 来设置开始延时;
以及其他⼀些便捷⽅法。

view.animate().translationX(500);
unknown_filename

ValueAnimator

ValueAnimator是整个属性动画机制当中最核心的一个类,属性动画的运行机制是通过不断地对值进行操作来实现的,我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。除此之外,ValueAnimator还负责管理动画的播放次数、播放模式、以及对动画设置监听器等,是一个非常重要的类。
可以在动画多的时候用

1
2
3
4
5
6
7
8
9
10
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);  
anim.setDuration(300);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentValue = (float) animation.getAnimatedValue();
Log.d("TAG", "cuurent value is " + currentValue);
}
});
anim.start();

ObjectAnimator

相比于ValueAnimator,ObjectAnimator可能才是我们最常接触到的类,因为ValueAnimator只不过是对值进行了一个平滑的动画过渡。而ObjectAnimator则就不同了,它是可以直接对任意对象的任意属性进行动画操作的,比如说View的alpha属性。 它其实是继承自ValueAnimator的,底层的动画实现机制也是基于ValueAnimator来完成的,因此ValueAnimator仍然是整个属性动画当中最核心的一个类。

1
2
3
4
5
ObjectAnimator oa = ObjectAnimator.ofFloat(bt, "translationX", 0, 100) ;//位移
ObjectAnimator oa = ObjectAnimator.ofFloat(bt, "scaleY", 0.1f, 2);//缩放
ObjectAnimator oa = ObjectAnimator.ofFloat(bt, "alpha", 0.1f, 1);//透明
ObjectAnimator oa = ObjectAnimator.ofFloat(bt, "rotation", 20, 270);//旋转
oa.start();

属性动画的优势在于,可以为⾃定义属性设置动画。

1
ObjectAnimator animator = ObjectAnimator.ofObject(view,"radius", Utils.dp2px(200));

另外,⾃定义属性需要设置 getter 和 setter ⽅法,并且 setter ⽅法⾥需要调⽤invalidate() 来触发重绘:

1
2
3
4
5
6
7
public float getRadius() {
return radius;
}
public void setRadius(float radius) {
this.radius = radius;
invalidate();
}

设置旋转起点

1
2
3
4
5
6
mArrowImageView.setPivotX(mArrowImageView.getMeasureWidth() / 2);
mArrowImageView.setPivotY(mArrowImageView.getMeasureHeight() / 2);
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(
mArrowImageView, "rotate", fromDegress, toDegress);
objectAnimator.setDuration(100);
objectAnimator.start();

可以使用reverse,就不需要重新创建个动画了

Interpolator

插值器,⽤于设置时间完成度到动画完成度的计算公式,直⽩地说即设置动画的速度曲线,通过 setInterpolator(Interpolator) ⽅法来设置。常⽤的有 AccelerateDecelerateInterpolator、
AccelerateInterpolator、DecelerateInterpolator、LinearInterpolator 。

差值器和估值器是什么?
Interpolator 负责控制动画变化的速率,使得基本动画能够以匀速、加速、减速、抛物线速率等各种速率变化。
TypeEvaluator 设置属性值,从初始值过度到结束值的变化具体数值。

PropertyValuesHolder

⽤于设置更加详细的动画,例如多个属性应⽤于同⼀个对象:

1
2
3
4
PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("radius", 
Utils.dp2px(200));
PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("offset", Utils.dp2px(100));
ObjectAnimator animator = PropertyValuesHolder.ofPropertyValuesHolder(view, holder1, holder2);

或者,配合使⽤ Keyframe ,对⼀个属性分多个段:

1
2
3
4
5
6
Keyframe keyframe1 = Keyframe.ofFloat(0,Utils.dpToPixel(100));
Keyframe keyframe2 = Keyframe.ofFloat(0.5f,Utils.dpToPixel(250));
Keyframe keyframe3 = Keyframe.ofFloat(1,Utils.dpToPixel(200));
PropertyValuesHolder holder =PropertyValuesHolder.ofKeyframe("radius", keyframe1,
keyframe2, keyframe3);
ObjectAnimator animator =ObjectAnimator.ofPropertyValuesHolder(view, holder);

AnimatorSet

将多个 Animator 合并在⼀起使⽤,先后顺序或并列顺序都可以:

1
2
3
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(animator1, animator2);
animatorSet.start();

TypeEvaluator

⽤于设置动画完成度到属性具体值的计算公式。默认的 ofInt() ofFloat() 已经有了⾃带的 IntEvaluator FloatEvaluator ,但有的时候需要⾃⼰设置Evaluator。例如,对于颜⾊,需要为 int 类型的颜⾊设置 ArgbEvaluator,⽽不是让它们使⽤ IntEvaluator

1
animator.setEvaluator(new ArgbEvaluator());

如果你对 ArgbEvaluator 的效果不满意,也可以⾃⼰写⼀个 HsvEvaluator :

1
2
3
4
5
6
7
8
public class HsvEvaluator implements
TypeEvaluator<Integer> {
@Override
public Object evaluate(float fraction, Object
startValue, Object endValue) {
...
}
}

另外,对于不⽀持的类型,也可以使⽤ ofObject() 来在创建 Animator 的同时就设置上 Evaluator,⽐如 NameEvaluator :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class NameEvaluator implements        
TypeEvaluator<String> {   
List<String> names = ...;   
@Override   
public String evaluate(float fraction, String  startValue, String endValue) {       
if (!names.contains(startValue)) {           
throw new IllegalArgumentException("Start value not existed");       
}       
if (!names.contains(endValue)) {           
throw new IllegalArgumentException("Endvalue not existed");       
}       
int index = (int) ((names.indexOf(endValue) - names.indexOf(startValue)) * fraction);       
return names.get(index);   
}
}
ObjectAnimator animator = ObjectAnimator.ofObject(view, "name", new NameEvaluator(), "Jack");

硬件加速

硬件加速是什么
使⽤ CPU 绘制到 Bitmap,然后把 Bitmap 贴到屏幕,就是软件绘制;
使⽤ CPU 把绘制内容转换成 GPU 操作,交给 GPU,由 GPU 负责真正的绘制,就叫硬件绘制;
使⽤ GPU 绘制就叫做硬件加速
怎么就加速了?
GPU 分摊了⼯作
GPU 绘制简单图形(例如⽅形、圆形、直线)在硬件设计上具有先天优势,会更快流程得到优化(重绘流程涉及的内容更少)
硬件加速的缺陷:
兼容性。由于使⽤ GPU 的绘制(暂时)⽆法完成某些绘制,因此对于⼀些特定的API,需要关闭硬件加速来转回到使⽤ CPU 进⾏绘制。

view动画的特殊使用场景

activity overridePendingTransition,可以是补间(下面的),也可以是熟悉动画
FragmentTransaction中的 setCustomAnimations 方法(不能是属性动画)

Image
Image.1


6.Android动画
http://peiniwan.github.io/2025/12/b6a0fdf8c755.html
作者
六月的雨
发布于
2025年12月16日
许可协议