Animator源码

做百分比的定时更新,发现用Handler.postDelay会卡,同样的逻辑放到Animator里就不会。拜读一下Animator是怎么做的。
主要是四个类:Animator(基类)、ValueAnimator(主要分析)、ObjectAnimator和AnimatorSet。

Animator:
  • Animator是不做线程同步的,所有方法都是口头要求同线程操作。Handler的postDelay是有同步的,每次都会在MessageQueue.enqueueMessage时做同步
  • 所有listener都是顺序执行的,均在UI线程被调用
  • 清空listener时会 mListeners.clear(); mListeners = null;
  • 因为AnimatorListener的回调不是很全,又加入了AnimatorPauseListener,做到了向前兼容
ValueAnimator:
  • 主要逻辑是:AnimatorHandler(内部类,Runnable)持有当前线程(ThreadLocal实现)start的所有Animator。如果需要执行,AnimatorHandler将自己post到Choreographer中,在Choreographer收到页面刷新信息后回调自己,在其所在的Looper执行所有更新操作
  • a%b的语义是while(a>b) a -= b;float、double都是这个语义
  • 维持一些不变式,比如说startTime + fractionTime = now;会让程序简洁
  • 时间使用SystemClock.uptimeMillis()
  • Animator.setFrameDelay是直接给Choreographer设FrameDelay,不一定生效
  • 对于同一线程可能修改的容器,可以使用退化的CopyOnWrite策略
  • 不论在什么线程上启动,Animator的所有操作都在UI线程上执行,但是不同线程上启动的Animator之间的运行时间是不会互相影响的,相同线程的Animator会在同一队列顺序执行
  • 实际上Animator多出很多变量来减少中间计算,开发者没有这样做,很可能是为了减少维持不变式的成本,减少出错的概率
分析

之所以用Handler会卡,用Animator不卡,最重要的原因是Animator的间隔和时序都是通过Choreographer控制的,与页面刷新的节奏是同步的,而Handler可能会因为各种原因导致掉帧,看起来卡。为了保持Choreographer尽量的流程,增加的ThreadLocal区分不同的Animator。
使用不当(未及时remove listener,没有cancel Animator)可能有内存泄露。

架构

Animator的架构设计非常有趣,划分的非常细致,以至于我一直把Interpolator理解错了。
抽象来看,ValueAnimator就是一个时间到值的函数映射及时间自运行的功能,即一个自更新的f(t)(在一个二维坐标系中,自动变换x获取y)。而真实的ValueAnimator对f进行了拆分。
- ValueAnimator:对t进行了归一化,即a = t/total,把x轴的进度都变为0-1。这样后面的所有运算都是统一的算法。可以看到BounceInterpolator中,所有的值都是写死的,非常容易做出通用的算法
- Interpolator:a到x的映射,会出现不同的映射进度,x = f1(a)。所有不同的映射、弹跳等变换都是在这一层。这里面,所有的变化都发生在x轴上,充分隔离了传入的y范围(ValueAnimator.ofInt)的影响,也保证了这是一个单纯的分段函数,不会出现两级分段的情况
- PropertyHolder:x到y的映射f2(x),这是最终函数值获取,大部分来讲就是一个线性变换/分段函数。这里面的输入就是进行了一大波变换后的x了,这里面又非常简单的做了一系列的变化,非常清爽
这样一个架构比我主观上yy的直接Interpolator是f(t)要有不小的优势。主要有几方面:
- f(t)真正的入参还是有y取值范围的,也就是说f(t, y[])。增加了Interpolator和归一化,可以真正的让映射f2只有一个入参就是x,而y[]是作为算法的一部分存在的
- 同样,各种速率变换本身也是有多入参的,包括了y[],duration和t。归一化剔除了duration,只做x轴上的映射剔除了y[],真的是简化了思考和算法

大概这就是牛逼的设计吧,虽然不是那么好理解,要细细品味才能参透。但是不管从哪方面来讲,都比直来直去的更合理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity Animator 源码是 Unity 引擎中负责控制角色动画的一个重要模块。Animator 在 Unity 中属于组件之一,用于控制角色或对象的动画状态和过渡。它可以支持使用 Animator Controller 管理动画状态机,并且可以通过编写代码来动态控制动画的播放。 Unity Animator 源码是 Unity 引擎的一部分,它主要包含了实现 Animator 功能所需的各个类和方法。具体来说,Animator 源码包含了以下几个方面的内容: 1. 状态机:Animator 源码中实现了状态机的逻辑,包括状态的切换、过渡和权重的管理等。它通过状态机图来管理各个状态以及状态之间的过渡关系。 2. 动画控制器:Animator 源码还包含了 AnimatorController 的实现,通过 AnimatorController 可以将状态机图中的状态和过渡组织起来,方便管理和控制角色动画的播放。 3. 动画事件:Animator 源码中还实现了动画事件的处理逻辑,可以在指定的动画帧上触发自定义的事件,例如播放声音、改变角色属性等等。 4. 动画播放:Animator 源码提供了对动画的播放和控制的方法,开发者可以通过编写代码来控制动画的播放速度、循环模式、渐变等。 通过研究 Animator 源码,开发者可以更加深入地了解 Unity 引擎中动画系统的工作原理,并且可以根据需求进行自定义扩展。此外,了解 Animator 源码还可以帮助开发者更好地优化动画性能,例如减少状态机和过渡的复杂度,优化动画资源加载等。 总之,Animator 源码是 Unity 引擎中控制角色动画的重要组成部分,通过研究源码可以深入理解动画系统的实现原理,并且可以利用它来实现更高级的动画控制功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值