Android 开发艺术探索笔记(16)

插值器和估值器
TimeInterpolator中文翻译为时间插值器,它的作用是根据时间流逝的百分比来计算出当前属性改变的百分比。系统预置了一些插值器(线性插值器,加减速插值器等)。
TypeEvaluator的中文翻译为类型估值算法,也叫估值器,它的作用是根据当前属性改变的百分比来计算改变后的属性值。系统也预置了一些估值器。
插值器和估值器的作用是让动画进行非匀速运动。

Android 开发艺术探索笔记(16)_第1张图片
这是一组动画从0到40ms完成的一个匀速动画,这时候我们要去修改这个动画变成非匀速动画。
动画的默认刷新率是10ms/帧,所以动画有5帧,以第三帧 x=20来说,时间流逝的百分比是50%(20/40=0.5),意味时间过了一半。那x应该改变多少呢?这个就要有插值器和估值器来进行确定。一般情况下的插值器是线性插值器,当时间流逝一半时,x的改变也是一半,所以是0.5,所以线性插值器实现的是匀速动画。
Android 开发艺术探索笔记(16)_第2张图片
这里是线性插值器(LinearInterpolator)的源码,可以看到getInterpolation中返回的值和输入的值一样,当返回值是0.5,说明输入值也是0.5。而x具体变成具体什么值,就要看估值器。
Android 开发艺术探索笔记(16)_第3张图片
evaluate方法中的三个参数为估值小数,一个为起始值,一个为结束值。对应t=20ms的例子来说就是evaluate(0.5,20,40),返回得值为20,所以x=20,这就是由来。
由代码又知道,我们可以通过去实现接口Interpolator和TypeEvaluator来自定义插值器和估值器。

属性动画监听器
属性动画提供了监听器用于监听动画的播放过程。主要有如下两个接口:
AnimatorUpdateListener和AnimatorListener。
AnimatorListener可以监听动画的开始、结束、取消和重复播放。
AnimatorUpdateListener会监听整个动画过程,即每走一帧,就会监听一帧。

对任意属性做动画
属性动画要求动画作用的对象提供该属性的get和set方法,属性动画根据外界传递的该属性的初始值和最终值,以动画的效果多次去执行set方法。每次传给set方法的值都不一样,随着时间推移,这个值将越来越接近最终值。所以我们对object的属性abc做动画,如果想让动画生效,要同时满足两个条件:
(1)object必须要提供setAbc方法,如果动画没有提供初始值,还要提供getAbc方法。
(2)object的setAbc对属性abc所做的改变必须能够通过某种方法反映出来,比如会带来UI的改变之类的(否则动画无效果但不会crash)。
比如我们给以一个button来加一个变宽的动画,button的getWidth能够得到width,但是setWidth却不能改变width,因为在button继承的TextView中的setWidth是设置最小宽度和最大宽度,所以满足了第一个条件没有满足第二个条件。解决方法有:
(1)如果你有权限就给你的属性加上set和get方法。
(2)用一个类来包装原始对象,间接为其提供get和set方法。
(3)采用ValueAnimator,监听动画过程,自己实现属性改变。

属性动画的工作原理
这里就不贴源码了,其实很简单,就是判断先将当前动画、等待动画、延迟动画中有和当前动画相同的动画,则将其取消,最后将当前动画start。

使用动画的注意事项

  • OOM
    帧动画中出现了大量的尺寸过大的图片
  • 内存泄漏
    有些动画会无限循环,所以要在Activity退出时及时停止。
  • 兼容性问题
  • View动画问题
    View动画是对动画做影像动画,并没真正改变View的状态
  • 不要使用px
  • 动画元素的交互
    属性动画的单击事件触发在移动后的位置,View则在之前的位置。
  • 硬件加速
    使用动画的过程中尽量使用硬件加速,能保证动画的平滑和流畅性。

理解Window和WindowManager

Window是一个窗口,Window的具体实现位于WindowManagerService中,WindowManager可以管理Window,并以IPC的形式与WindowManagerService交互。
首先使用WindowManager来添加一个Window,代码如下:
这里写图片描述
Android 开发艺术探索笔记(16)_第4张图片
上述的代码将一个Button添加屏幕的(100,300)坐标上。
WindowManager.LayoutParams中的flags和type这两个参数比较重要。
下面是几个重要的flags:
Android 开发艺术探索笔记(16)_第5张图片
Type参数表示的是Window的类型,有三种,分别是应用Window,子Window和系统Window。
应用类Window对应着一个Activity,子Window不能单独存在,它需要附属在父Window中,比如常见的Dialog就是子Window。系统Window就是需要声明权限才能创建的Window,比如Toast。
它们都有分层,大的级别在上面,Window的范围是1-99,子Window是1000-1999,系统则是2000-2999,可以通过LayoutParams的的type设置。
WindowManager的功能比较简单,就是添加View、更新View、删除View。这三个方法都定义在接口ViewManager中。而WindowManager继承了ViewManager。

Window的内部机制
每一个Window都对应着一个View和一个ViewRootImpl,Window和View通过ViewRootImpl来建立联系,因此View实际上是不存在的,它是以View的形式存在。实际中无法直接应用Window,要通过WindowManager。

  • Window的添加
    通过WindowManager的addView来实现。WindowManager是一个接口,它真正实现的是WindowManagerImpl类。在这个类中Window的三大操作如下:
    Android 开发艺术探索笔记(16)_第6张图片
    可以看到所有的操作都是交给了WindowManagerGlobal来处理。这是典型的桥接模式。WindowManagerGloabl的addView的源码为:
    Android 开发艺术探索笔记(16)_第7张图片
    Android 开发艺术探索笔记(16)_第8张图片
    Android 开发艺术探索笔记(16)_第9张图片
    上面是创建每个Window所对应的View、每个Window所对应的ViewRootImpl,所有的参数,然后将View添加到这些列表中。
    然后通过ViewRootImpl来更新界面并完成Window的添加过程。
    这个步骤由setView来完成,其内部有requestLayout,用来进行异步刷新。
    最后通过WindowSession来完成Window的创建。实现的类是Session,所以说这是Window的添加是一次IPC调用,它最后是交由WindowManagerService处理,WindowManagerService会为每一个应用保留一个单独的Session。

你可能感兴趣的:(Android,开发艺术探索)