Android动画

Android动画分类:

  • 视图动画:补间动画、逐帧动画
  • 属性动画

视图动画

补间动画

可以在xml中定义动画,然后通过AnimationUtils.loadAnimation()方法加载动画资源,通过view.startAnimation实现动画。
也可以在代码中实现动画的创建
同样的,可以在xml动画资源中添加插值器,也可以在代码中添加插值器
常见实例:旋转加载动画,对一个view设置pivotX和pivotY为自身高宽的一半,然后能够设置旋转动画,设置重复;
网易云音乐按键重复波浪动画,设置几个重叠的圆形view,对每个view设置相同的scale+alpha动画,并设置不同的启动时间,这样就能创造出这样的效果惹。

逐帧动画

使用AnimationDrawable类控制播放。


属性动画

视图和属性有下列三点不同,视图动画在android.view.animation中,属性动画在android.animation中。视图动画命名为XXXAnimation,属性动画为XXXAnimator

  • 为什么要有属性动画:
    视图动画只有有限的维度能进行变换操作,没拓展性;
    视图动画只能对view做操作;
    视图动画只改变了view的显示效果,而没有改变其真正属性

它实际上是一种不断地对值进行操作的机制,并将值赋值到指定对象的指定属性上,可以是任意对象的任意属性

属性动画也可以在xml中定义

核心类:ValueAnimator,其常用实现类 ObjectAnimator
利用AnimatorSet将不同动画组合起来,AnimatorSet的setduration对动画起始没束缚作用,只能控制动画是否同时开始或开始顺序
监听器有AnimatorListener,其实现类有AnimatorListenerAdapter。
valueAnimator有监听器AnimatorUpdateListener

  • PropertyValuesHolder
    保存了动画中所需要操作的属性和对应的值,举例
    public static PropertyValuesHolder ofFloat(String propertyName, float... values)
    这个和ObjectAnimator的ofFloat方法基本相似,只是没有了操作对象如textview。
    实际上,我们平时通过ofFloat函数构造额动画,底层就是将传入额参数封装成PropertyValuesHolder来保存的。
    调用实例如下:
    ObjectAnimator.ofPropertyValuesHolder(Object target, PropertyValuesHolder...values)
    就酱,惹

  • KeyFrame 关键帧,在不使用插值器额情况下实现动画的速率变化,以fraction:value的形式

KeyFrame frame0 = KeyFrame.ofFloat(0.3f,12f);

表示进度哎30%时候动画数值为12f,常常和PropertyValuesHolder公用

KeyFrame frame0 = KeyFrame.ofFloat(0f,3f);
KeyFrame frame1 = KeyFrame.ofFloat(1f,4f);
PropertyValueHolder frameHolder = PropertyValueHolder.ofKeyFrame("ratation",frame0,frame1);
Animator animator = ObjectAnimator.ofPropertyValueHolder(mTv,frameHolder);

使用插值器,当前keyframe设置插值器作用范围是上一个keyFrame到当前keyFrame。动画的开始和结束以实际起始帧和结束帧为界定,至少需要两个关键帧

  • 利用SVG制作动画
    创建xml将svg和动画xml文件关联起来,然后在代码中使用。

  • ViewPropertyAnimator
    1、ViewPropertyAnimator是对view对象的动画进行封装的api,它不属于属性动画或者视图动画,是一个独立的新增api,主要优点是调动方法更加面向对象,适用场景是对view的多个内置属性同时做动画:
    view.animate(500).x(500).y(500).setduration(1000);
    2、ViewPropertyAnimator主要针对view的内置属性进行动画操作。
    虽然不继承自Animator,仍然能够调用Animator的Listener。
    3、ViewPropertyAnimator没有显式调用start函数,实际上会在下一次界面刷新时候启动。继续声明动画,会将动画添加到下一帧开始的动画列表中。
    4、性能方面ViewPropertyAnimator没有采用想ObjectAnimator一样的反射或者JNI技术,而是根据预设的每个动画帧计算出对应的所有属性值,调用一次invalidate进行重绘;不像ObjectAnimator给每个属性单独计算,单独重绘导致的性能损耗。所以它相对于ObjectAnimator和组合动画性能有所提升。当然一般用属性动画性能也OK的。

  • 案例分析:
    1、如何对一个圆形自定义view做移动动画
    对point添加估值器,设置起始点位置,设置point的动画,在动画更新的时候,invalidate,圆形的圆心设置为当前point的坐标,在ondraw方法中绘制圆形。
    2、如何对一个圆形做颜色变换
    对该view添加color的set、get方法,设置color的估值器,设置起始颜色值并根据这些条件启动动画,在set方法中更新paint的颜色值并invalidate,重新绘制该圆形。

动画优化

  • 合理刷新
    1、只有在视图内容真正改变时才 invalidate
    2、尽量用带 4 个参数的 invalidate 方法刷新,比如 invalidate(0, 0, 200, 400);
  • 布局优化
    除了性能优化中提到的布局优化
    尽量使用 GONE 替换 INVISIBLE
  • 绘制优化
    除了性能优化中提到的绘制优化
    1、尽量减少不必要的背景设置,图片尽量压缩处理
    2、自定义 View 绘制时使用 canvas.clipRect()指定绘制区域
    3、当一个 View 被其他 view 完全遮挡住了的话,最好把被遮挡的 view 移除掉。
    4、去掉 Window 的默认背景。
    当我们使用了Android自带的一些主题时,window会被默认添加一个纯色的背景,
    这个背景是被 DecorView 持有的。当我们自定义布局时又添加了一张背景图或者设
    置背景色,那么 DecorView 的 background 此时对我们来说是无用的,但是它会产
    生一次 Overdraw,带来绘制性能损耗。
    去掉 window 的背景可以在 onCreate()中 setContentView()之后调用。
    getWindow().setBackgroundDrawable(null);
    或者在 theme 中添加
    android:windowbackground="null";
  • 动画逻辑优化
    1、帧动画,耗费内存资源大,能不用就不用;补间动画使得 view 重绘非常频繁;
    属性动画通过修改实际属性来实现动画效果,相比于补间动画,重绘次数要少得

    2、减少 animator 的创建,如果有多个 animator,尽量合并到一个 animator
    3、PropertyValuesHolder 和 keyframe 的使用
    4、使用 ViewPropertyAnimator
    5、尽量减少当前动画执行时的逻辑复杂度
    动画时,一些无关本次动画 UI 刷新的处理都可以先暂停,待动画结束时,再继续进行。
  • 减少view的数量
  • 尽量为所有分辨率创建资源
    减少不必要的硬件缩放,这会降低 UI 的绘制速度
  • 不要在绘制方法中创建对象
    一个常见的错误是,每一次渲染方法(比如,onDraw)被调用的时候都创建一个新的 Paint
    或一个新的 Path。这样可能会导致频繁 GC,影响性能。
  • 硬件加速和层的使用
    Android3.0 引入了硬件加速的概念,用来提高渲染速度。硬件加速渲染时,若只有一个
    view 发生变化,只会刷新这个 view。通过 OpenGLRender 负责将 RootView 中的 DisplayList 渲
    染到屏幕上。
  • 不要太频繁的修改 path
    如果在一个支持硬件加速的 Canvas 上调用 Canvas.drawPath(), 系统会首先在 CPU 上绘
    制这些 path,然后把它传递给 GPU。如果你的 path 对象很大,那最好避免在每一帧之间修
    改它 。drawRect/Circle/Oval/RoundRect()比 drawPath 更加高效,因此最好使用它们替代相应
    的 drawPath 操作
  • 不要太频繁的修改 Bitmap
  • 谨慎使用alpha
    当你用 setAlpha(),AlphaAnimation,或 ObjectAnimator 把一个 view 设为透明,需要先
    将 View 绘制出来,然后做 Alpha 转化,最后将转换后的效果绘制在界面上。通俗点说,做
    Alpha 转化就需要对当前 View 绘制两遍,绘制效率会大打折扣,耗时会翻倍。当在一个非
    常大的 view 上应用透明度时,应考虑把 view 的 layer 类型设置为
    LAYER_TYPE_HARDWARE。
    view.setLayerType(LAYER_TYPE_HARDWARE);
    ...
    doSmoeThing();
    view.setLayerType(LAYER_TYPE_NONE);
  • 除法改乘法或位运算
    CPU 对于乘法的计算快于除法,尽量将除法运算换成乘法或者位运算

很强了,参考资料:
https://github.com/LeeFranz/tech-documents
https://developer.android.com/topic/performance/index.html
https://developer.android.google.cn/guide/topics/graphics/hardware-accel.html
https://developer.android.google.cn/guide/topics/graphics/prop-animation.html

你可能感兴趣的:(Android动画)