Android 开发艺术探索笔记之七 -- Android 动画深入分析

写在最前:我之前整理过关于 Android 动画的两篇文章,所以本文更多的只是对之前遗漏的知识点加以补充,重复的部分不再详细描述。

附上原本整理的两篇 动画相关 的文章:

  • Android 视图动画(View Animation) 使用详解
  • Android 属性动画(Property Animation) 使用详解

欢迎大家提出各种意见!


学习内容:

  • View 动画
    • 典型的四种变换(补间动画) 和 帧动画
    • 特殊使用场景
  • 属性动画
  • 动画的注意事项

1. View 动画

除非特别说明,一般 View 动画指的就是四种变换(补间动画);指 帧动画 时会特别说明。

1.1 View 动画的分类

四类变换及复合:

名称 Java子类 xml关键字 说明
透明度动画 AlphaAnimation 放置在res/anim/目录下 透明度渐变
旋转动画 RotateAnimation 放置在res/anim/目录下 视图旋转
缩放动画 ScaleAnimation 放置在res/anim/目录下 放大/缩小 视图尺寸大小
平移动画 TranslateAnimation 放置在res/anim/目录下 视图位置移动
复合动画 AnimationSet 放置在res/anim/目录下 一个持有其它动画元素alpha、scale、translate、rotate或者其它set元素的容器

具体使用

见 Android 视图动画(View Animation) 使用详解

插值器

见 Android 视图动画(View Animation) 使用详解

1.2 自定义 View 动画

简单而复杂:

  • 简单:只需要 继承 Animation 抽象类,重写 initialize 和 applyTransformation 方法即可,其中 在 initialize 方法中做初始化工作,在 applyTransfromation 方法中进行矩阵变换
  • 复杂:自定义 View 动画主要是矩阵变换的过程。

1.3 帧动画

见 Android 视图动画(View Animation) 使用详解

2. View 动画的特殊使用场景

本小节主要介绍在 ViewGroup 中控制子元素的出场效果,以及在 Activity 中实现不同 Activity 之间的切换效果。

2.1 LayoutAnimation

LayoutAnimation 作用于 ViewGroup,为 ViewGroup 指定一个动画,然后它的子元素出场时就会具有这种动画效果。常用于 ListView。

使用步骤

  1. 定义 LayoutAnimation,如下:

    //res/anim/naim_layout.xml
    
    

    属性说明:

    ​ android:delay:子元素开始动画的时间延迟,表示占播放周期的比例。
    ​ andorid:animationOrder:子元素动画的顺序,有三种值:normal、reverse 和 random。
    ​ android:animation:子元素具体的入场动画。

  2. 为子元素指定具体的入场动画,如:

    // res/anim/anim_item.xml
    
    
        
        
    
    
  3. 为 ViewGroup 指定 android:layoutAnimation 属性:android:layoutAnimation="@anim/anim_layout"

    除在 XML 中指定 LayoutAnimation 外,还可以通过 LayoutAnimationController 实现:

    Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item);
    LayoutAnimationController controller = new LayoutAnimationController(animation);
    controller.setDelay(0.5f);
    controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
    listview.setLayoutAnimation(controller)
    

2.2 Activity 的切换效果

如何实现:

  • 在调用 startActivity(Intent) 或者 finish() 之后,调用 overridePendingTransition(int enterAnim, int exitAnim) 方法
  • enterAnim 参数表示打开时所需的动画资源 id;exitAnim 参数表示关闭时所需的动画资源 id。

关于 Fragment 的切换动画:

  • 使用 support-v4 兼容包
  • 通过 FragmentTransaction 的 setCustomAnimations() 方法添加切换动画(动画需要是 View 动画)。

3. 属性动画

3.1 使用属性动画

具体见 Android 属性动画(Property Animation) 使用详解

知识点:

  • ValueAnimator
  • ObjectAnimator
  • AnimatorSet

上述 java 代码 以及 xml 两种使用方式。

3.2 理解插值器和估值器

估值器见 Android 属性动画(Property Animation) 使用详解
插值器见 Android 视图动画(View Animation) 使用详解
知识点:

  • 插值器TimeInterpolator 和 估值算法 TypeEvaluator 的理解
  • 系统预置的 插值器/估值算法
  • 自定义插值器需要实现 Interpolator 或者 TimeInterpolator
  • 自定义估值算法需要实现 TypeEvaluato,重写 evaluate 方法

3.3 属性动画的监听器

具体见 Android 属性动画(Property Animation) 使用详解
知识点:

  • AnimatorUpdateListener
    • 监听动画开始、结束、取消和重复播放
  • AnimatorListener
    • 监听整个动画过程(每一帧)

3.4 对任意属性做动画

原理简述:

属性动画要求动画作用的对象提供该属性的 get 和 set 方法,属性动画根据外界传递的该属性的初始值和最终值,以动画的效果多次调用 set 方法,随着事件的推移,所传递的值越来越接近最终值。

因此需要满足两个条件:

  1. object 必须提供 setXxx 方法,如果动画没有传递初始值,那么还需要提供 getXxx 方法,用作获取 初始值(此条件不满足,直接 crash)
  2. object 的 setXxx 对属性 xxx 所作的改变必须通过某种方法反映出来,比如带来 UI 的改变(此条件不满足,不会 crash,但是动画无效果)

如何满足上述两个条件?

  1. 如果有权限,给对象加上 set 和 get 方法
  2. 用一个类被包装原始对象,间接提供 get 和 set 方法
  3. 采用 valueAnimator,监听动画过程,自己实现属性的改变

3.5 属性动画的工作原理

源码流程:

Android 开发艺术探索笔记之七 -- Android 动画深入分析_第1张图片
简要方法调用流程

说明:

  • ObjectAnimator.start():会取消 当前动画、等待的动画和延迟的动画中相同的动画,然后调用父类 ValueAnimator 的 start 方法
  • ValueAnimator.start():属性动画运行在 有 Looper 的线程中
  • AnimatorHandler.start():AnimatorHandler 并不是 Handler,而是一个 Runnable。它会调用到 JNI 层(???),最终 JNI 层会调回来,然后 调用它的 run 方法。
  • calculateValue 方法计算每帧动画所对应的属性的值 。

再分析一下 get 和 set方法的调用:

  1. PropertyValuesHolder.setupValue:初始化时,如果属性的初始值没有提供,会通过 反射 调用 get 方法。
  2. PropertyValuesHolder.setAnimateValue:当动画下一帧来临的额时候,通过 反射 调用 set 方法设置属性值。

4. 使用动画的注意事项

主要分为以下几类:

1. OOM 问题
主要出现在帧动画中,数量较多且图片较大时极易出现 OOM。因此尽量避免使用帧动画。

2. 内存泄漏
​属性动画中有一类无限循环的动画,这类动画需要在 Activity 退出时即时停止,否则将导致 Activity 无法释放从而造成内存泄漏,通过验证后发现 View 动画并不存在此问题。

3. 兼容性问题
​Android 3.0 以下的动画适配。。现在应该不需要考虑这个问题了。

4. View 动画的问题
​View 动画是对 View 的影像做动画,并不是真正改变 View 的状态,因此有时会出现动画完成后 View 无法隐藏的现象,即 setVisibility(View.GONE) 失效,此时调用 view.clearAnimation() 清楚 View 动画即可。

5. 不要使用 px
尽量使用 dp,使用 px 可能导致不同设备上显示效果不同。

6. 动画元素的交互
View 动画不改变事件触发位置,属性动画本质改变属性,因此事件出发位置随之改变。

7. 硬件加速
建议开启硬件加速,提高动画流畅性。

你可能感兴趣的:(Android 开发艺术探索笔记之七 -- Android 动画深入分析)