ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

【阅读源码--Android】动画之ValueAnimator--1

【阅读源码--Android】动画之ValueAnimator--1 引言文档是指挥AI写的我觉得比较重要的地方都补充了些内容读源码系列目的就是学习和总结所以内容比较偏粗线条概括性的除非是特别细的需要注意的点大部分都是提纲性的。AI分析总结并写出文档并不能代替读代码因为不读代码并不会发现有意思的地方但是AI写文档和画图确实比人快所以后续文章都会让AI来写。1. 概述ValueAnimator是 Android 属性动画系统的核心时序引擎。它本身不操作任何对象属性仅负责在给定时长内计算动画值并通过回调通知调用者。我觉得time-fraction-value的解耦抽象是个很好的点在这个基础上可以做到很好的通用性。2. 核心架构2.1 Animator 包整体架构android.animation 包 │ ├── Animator (abstract, implements Cloneable) │ │ 动画基类定义生命周期接口start/cancel/end/pause/resume │ │ 管理 AnimatorListener / AnimatorPauseListener │ │ │ ├── ValueAnimator │ │ │ 核心时序引擎计算动画值但不操作属性 │ │ │ 持有 PropertyValuesHolder[]、TimeInterpolator │ │ │ 实现 AnimationHandler.AnimationFrameCallback │ │ │ │ │ └── ObjectAnimator │ │ 在 ValueAnimator 基础上自动将动画值设置到目标对象的属性 │ │ 通过 PropertyValuesHolder 的 setter/getter 反射或 Property 接口赋值 │ │ 支持自动取消同目标同属性的动画 │ │ │ ├── AnimatorSet │ │ 组合多个 Animator支持 together并行和 sequentially顺序两种编排 │ │ 通过 pulseAnimationFrame() 驱动子 Animator不依赖 Choreographer 直接调度 │ │ │ ├── TimeAnimator │ │ 简单封装每帧通过 TimeListener 回调当前时间不计算值 │ │ │ ├── StateListAnimator │ │ 根据 View 状态切换不同的 Animator │ │ │ └── RevealAnimator │ 圆形揭示动画ViewAnimationUtils.createCircularReveal │ ├── AnimationHandler │ │ 帧调度中枢ThreadLocal 单例 │ │ 管理 mAnimationCallbacks 列表所有活跃 Animator │ │ 管理 mCommitCallbacks 列表需要 jank 补偿的 Animator │ │ 通过 AnimationFrameCallbackProvider 驱动默认使用 Choreographer │ │ 支持后台暂停无限动画省电 │ │ │ ├── AnimationFrameCallback (interface) │ │ doAnimationFrame(frameTime) ← 帧计算入口 │ │ commitAnimationFrame(frameTime) ← 帧提交入口jank 补偿 │ │ │ └── AnimationFrameCallbackProvider (interface) │ postFrameCallback() / postCommitCallback() │ getFrameTime() / getFrameDelay() / setFrameDelay() │ 默认实现 MyFrameCallbackProvider → 封装 Choreographer │ ├── 值计算体系 │ ├── PropertyValuesHolder 持有属性名 Keyframes Evaluator Converter │ │ ├── IntPropertyValuesHolder int 特化JNI setter 加速 │ │ ├── FloatPropertyValuesHolder float 特化JNI setter 加速 │ │ ├── MultiFloatValuesHolder 多参数 float setter │ │ └── MultiIntValuesHolder 多参数 int setter │ │ │ ├── Keyframes (interface) │ │ └── KeyframeSet 默认实现 │ │ ├── IntKeyframeSet int 特化避免装箱 │ │ ├── FloatKeyframeSet float 特化避免装箱 │ │ └── PathKeyframes Path 特化 │ │ │ ├── Keyframe (abstract) │ │ ├── IntKeyframe │ │ ├── FloatKeyframe │ │ └── ObjectKeyframe │ │ │ ├── TypeEvaluatorT (interface) fraction → 动画值 │ │ ├── IntEvaluator / FloatEvaluator │ │ ├── ArgbEvaluator 颜色sRGB 线性空间插值 │ │ ├── PointFEvaluator / RectEvaluator │ │ └── FloatArrayEvaluator / IntArrayEvaluator │ │ │ └── TypeConverterT,V (interface) 动画值 → setter 参数类型转换 │ └── BidirectionalTypeConverter 双向转换支持从目标对象反向获取值 │ ├── TimeInterpolator (interface) 原始 fraction → 插值 fraction │ 实现在 android.view.animation 包 │ LinearInterpolator / AccelerateInterpolator / DecelerateInterpolator │ AccelerateDecelerateInterpolator / BounceInterpolator / OvershootInterpolator │ AnticipateInterpolator / AnticipateOvershootInterpolator / CycleInterpolator │ PathInterpolator │ └── 辅助类 ├── AnimatorListenerAdapter 空实现适配器 ├── AnimatorInflater 从 XML 加载 Animator └── AnimatorConstantState 缓存 ConstantState避免重复加载2.2 帧驱动机制Choreographer → Animator┌─────────────────────────────────────────────────────────────────────┐ │ Vsync 信号 (硬件) │ └──────────────────────────────┬──────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ Choreographer │ │ │ │ 收到 vsync 后按回调类型顺序执行 │ │ │ │ CALLBACK_ANIMATION ──→ AnimationHandler.mFrameCallback.doFrame() │ │ CALLBACK_INSETS_ANIMATION │ │ CALLBACK_TRAVERSAL ──→ View 绘制流程measure/layout/draw │ │ CALLBACK_COMMIT ─────→ AnimationHandler 的 commit 回调 │ └──────────────────────────────┬──────────────────────────────────────┘ │ ┌──────────────────────┴──────────────────────┐ │ │ ▼ CALLBACK_ANIMATION ▼ CALLBACK_COMMIT │ (帧开始遍历之前) │ (遍历之后帧提交) │ │ ┌───────┴─────────────────────────────────┐ ┌────────┴────────────────────────────┐ │ AnimationHandler.doAnimationFrame() │ │ AnimationHandler.commitAnimationFrame()│ └─────────────────────────────────────────┘关键时序说明阶段Choreographer 回调类型时机作用动画帧计算CALLBACK_ANIMATIONvsync 后遍历之前计算动画值触发 View 重绘View 遍历CALLBACK_TRAVERSAL动画帧之后measure / layout / draw帧提交CALLBACK_COMMIT遍历之后jank 补偿修正 startTimecommitAnimationFrame 的意义首帧从doAnimationFrameCALLBACK_ANIMATION到实际绘制CALLBACK_COMMIT之间可能有显著延迟因 measure/layout/draw 耗时。如果不补偿下一帧的animateBasedOnTime会认为已经过了很长时间导致跳帧。commitAnimationFrame将mStartTime对齐到实际绘制时间确保动画从正确的起点开始。2.3 值计算管线设计思想ValueAnimator 的核心设计思想是将时间解耦为三层抽象每一层职责单一、可独立替换Time → Fraction将真实流逝的时间毫秒归一化为[0, 1]的进度比例。这一层处理动画的时长、延迟、重复和反向播放但不关心值的具体类型。Fraction → Interpolated Fraction通过TimeInterpolator对原始 fraction 进行非线性映射控制动画的节奏加速、减速、弹跳等但不关心最终值是什么。Interpolated Fraction → Value通过TypeEvaluator将插值后的 fraction 转换为实际的动画值float、int、color、自定义对象等完成从抽象进度到具体值的映射。这种分层设计使得三者可以正交组合同一个TimeInterpolator可用于任何类型的动画同一个TypeEvaluator也可搭配不同的TimeInterpolator。Time、Fraction 与 Value 的关系真实时间 (ms) │ │ elapsed currentTime - mStartTime │ fraction elapsed / scaledDuration │ ▼ 原始 fraction ∈ [0, mRepeatCount 1] ← 时间→进度归一化 │ 1 表示进入重复迭代 │ │ getCurrentIteration() → 拆分为 iteration iterationFraction │ shouldPlayBackward() → 可能取 1 - iterationFraction │ ▼ 当前迭代 fraction ∈ [0, 1] ← 处理重复与反向 │ │ mInterpolator.getInterpolation(fraction) │ ▼ 插值 fraction ∈ ℝ可超出 [0,1] ← 节奏变换 │ 如过冲、弹跳会超出范围 │ │ mEvaluator.evaluate(fraction, startValue, endValue) │ 或 KeyframeSet.getValue(fraction) │ ▼ 动画值 (float / int / color / Object) ← 进度→值类型求值关键公式阶段公式说明时间→进度fraction (currentTime - mStartTime) / scaledDuration归一化为进度1表示重复进度→迭代iteration floor(fraction)iterFraction fraction - iteration拆分出当前迭代及迭代内进度迭代方向shouldPlayBackward ? (1 - iterFraction) : iterFractionREVERSE 模式下奇偶迭代方向交替节奏变换interpolated interpolator.getInterpolation(fraction)非线性映射输出可超出[0,1]进度→值value evaluator.evaluate(interpolated, start, end)线性插值start t * (end - start)多关键帧时的值计算当使用多个 Keyframe 时KeyframeSet.getValue()先定位 fraction 落入的区间[prevKf, nextKf]计算区间内比例intervalFraction再应用该区间的局部 Interpolator最后由 Evaluator 在两个 Keyframe 值之间插值。这相当于将整个动画分段每段独立插值。管线流程时间脉冲 (frameTime) │ ▼ doAnimationFrame(frameTime) ← 帧调度入口 │ ▼ animateBasedOnTime(currentTime) ← 计算总 fraction │ ▼ getCurrentIterationFraction() ← 计算当前迭代 fraction处理 repeat/reverse │ ▼ animateValue(fraction) ← 核心计算 │ ├─ mInterpolator.getInterpolation(fraction) ← 时间插值节奏控制 │ ├─ mValues[i].calculateValue(fraction) ← 类型求值值计算 │ └─ 通知 mUpdateListeners ← 回调调用者2.4 关键组件职责组件职责AnimationHandler帧调度通过 vsync/Handler 驱动doAnimationFrame()TimeInterpolator时间映射原始 fraction → 插值 fraction控制快慢节奏TypeEvaluator值映射插值 fraction → 实际动画值float/int/color/objectPropertyValuesHolder持有一组动画值内部封装 evaluator支持多属性并行动画3. 状态机start() │ ▼ ┌──── STARTED (mStartedtrue, mRunningfalse) │ │ │ (startDelay 0 时等待) │ │ │ ▼ 首帧到达 │ RUNNING (mRunningtrue) │ │ │ ┌─────┼─────┐ │ │ │ │ │ pause() │ cancel()/end() │ │ │ │ │ ▼ │ ▼ │ PAUSED │ END │ │ │ │ resume() │ │ │ │ └─────┘ │ │ ▼ IDLE (所有状态重置)状态字段字段含义mStartedstart()已调用可能还在 startDelay 中mRunning首帧已到达正在实际计算动画值mPaused暂停状态mInitializedPropertyValuesHolder已初始化mAnimationEndRequested已请求结束防止重复结束4. 时间管理4.1 关键时间字段字段含义mStartTime动画基准起始时间含 startDelay用于计算 elapsed timemLastFrameTime上一帧时间 0表示尚未进入帧循环mFirstFrameTime首帧时间mPauseTime暂停时刻用于 resume 时偏移mStartTimemStartTimeCommitted起始时间是否已固定首帧后通过commitAnimationFrame修正 jank4.2 Duration Scale两级缩放机制影响 duration 和 startDelayresolveDurationScale() mDurationScale 0 ? mDurationScale : sDurationScale getScaledDuration() mDuration * resolveDurationScale()sDurationScale系统全局缩放开发者选项/省电模式mDurationScale单实例覆盖overrideDurationScale-1f表示使用全局值
返回列表