Android 的动画系统历经四代 API 的演进,每一代都支持范围更广的运动效果 —— 从简单的视图级别变换,到基于物理的弹簧模型,再到窗口管理器的协同壳层转场动画。本章完整追踪动画数值从应用代码到合成器的整条执行路径,详细剖析各个主要子系统,并说明各模块如何通过 Choreographer 基于 VSYNC 的时序脉冲完成协同工作。
14.1 动画架构概述
14.1.1 四代动画
Android 提供四层独立的动画体系,每一层都构建在上一层基础之上:
| 代 | API 等级 | 包 / 位置 | 作用域 |
|---|---|---|---|
| 视图动画(遗留) | 1 | android.view.animation | 单个 View 的矩阵 + 透明度 |
| 属性动画 | 11 | android.animation | 任意 Object 对象的任意类型属性 |
| 转场框架 | 19 | android.transition | ViewGroup 范围内的场景变更编排 |
| 壳层转场 | 12L+ | com.android.wm.shell.transition | 跨窗口、跨任务的窗口管理器转场 |
除此之外,平台还提供专用子系统实现基于物理的运动(DynamicAnimation、SpringAnimation、FlingAnimation)、原生 RenderThread 动画(HWUI)以及 Drawable 层级动画(AnimatedVectorDrawable)。
14.1.2 端到端动画数据流
壳进程 系统服务窗口管理器 RenderThread 应用进程
14.1.3 时序基础设施
UI 线程上的全部动画共用同一个时序源:Choreographer。Choreographer 接收显示子系统的 VSYNC 信号,每一帧按顺序分发五类回调:
// frameworks/base/core/java/android/view/Choreographer.java,第321‑363行 CALLBACK_INPUT = 0 // 输入事件 CALLBACK_ANIMATION = 1 // 动画器帧回调 CALLBACK_INSETS_ANIMATION = 2 // 窗口Insets动画更新 CALLBACK_TRAVERSAL = 3 // View测量/布局/绘制 CALLBACK_COMMIT = 4 // 绘制完成提交;上报修正后的帧起始时间CALLBACK_COMMIT 阶段在视图遍历完成后执行,提供更准确的帧起始时间估算,视图层级可用来补偿复杂布局带来的延迟。注意:Android 17 中 AnimationHandler 不再为每个动画器单独注册 commit 回调;早期版本附加在每个 ValueAnimator 上的启动时间修正 / 卡顿补偿钩子已被移除(参见 §14.3.12)。
AnimationHandler 向 Choreographer 注册一个 FrameCallback,每次 VSYNC 到来时遍历所有已注册的 AnimationFrameCallback 实例,其中包含所有正在运行的 ValueAnimator 与 DynamicAnimation。
14.1.4 核心源码目录
| 目录 | 内容 | 大致代码行数 |
|---|---|---|
| frameworks/base/core/java/android/view/animation/ | 视图动画类 | ~5800 |
| frameworks/base/core/java/android/animation/ | 属性动画框架 | ~13400 |
| frameworks/base/core/java/android/transition/ | 转场框架 | ~9200 |
| frameworks/base/libs/hwui/ (Animator*) | 原生 HWUI 动画器 | ~830 |
| frameworks/base/core/java/android/view/Choreographer.java | 时序脉冲 | 1741 |
| frameworks/base/services/core/java/com/android/server/wm/ (anim) | 窗口管理器动画基础设施 | ~2400 |
| frameworks/base/libs/WindowManager/Shell/src/.../transition/ | 壳层转场 | ~8200 |
| frameworks/base/libs/WindowManager/Shell/src/.../back/ | 预测返回手势 | ~3200 |
| frameworks/base/core/java/com/android/internal/dynamicanimation/animation/ | 物理动画 | ~1750 |
14.1.5 线程模型
分析性能时,必须清楚每一类动画运行在哪一个线程:
关键点:ViewPropertyAnimator 与 AnimatedVectorDrawable(API25+)在 RenderThread 原生执行,不受 UI 线程卡顿影响。其余所有 Java 层动画均运行在 UI 线程,会受 GC、繁重布局或其他主线程任务干扰。
14.1.6 跨进程动画协同
现代 Android 动画经常跨多个进程:
动画逻辑运行在壳进程,但作用于应用进程的 Surface。这种解耦保证应用卡顿不会影响系统转场动画。
14.1.7 动画时长与缩放系数
Android 所有动画均受全局动画缩放配置控制。共有三个独立缩放因子:
| 配置项 | 作用对象 | 默认值 |
|---|---|---|
| animator_duration_scale | 属性动画(ValueAnimator 等) | 1.0 |
| window_animation_scale | 窗口打开 / 关闭动画 | 1.0 |
| transition_animation_scale | Activity 转场动画 | 1.0 |
可通过开发者选项或命令行修改:
adb shell settings put global animator_duration_scale 2.0 adb shell settings put global window_animation_scale 0.5 adb shell settings put global transition_animation_scale 0任意一项设置为 0,对应动画直接禁用,瞬间完成。
14.1.8 帧预算
60Hz 下单帧预算16.67ms;120Hz 下单帧预算8.33ms。动画回调必须在预算的一小部分内完成,给布局、绘制、GPU 留出时间。
| 阶段 | 60Hz 预算 | 120Hz 预算 |
|---|---|---|
| INPUT 回调 | ~1ms | ~0.5ms |
| ANIMATION 回调 | ~2ms | ~1ms |
| INSETS_ANIMATION | ~0.5ms | ~0.3ms |
| TRAVERSAL(布局 + 绘制) | ~10ms | ~5ms |
| GPU 渲染 | ~3ms | ~1.5ms |
| 合计 | ~16.5ms | ~8.3ms |
超出预算会发生掉帧(卡顿)。Choreographer 跳过超过 30 帧时会输出警告日志。
14.2 视图动画(遗留)
14.2.1 概述
视图动画从 API 1 开始存在,在绘制阶段给 View 应用 Transformation(矩阵 + 透明度)。重要特性:视图动画不会修改 View 真实布局属性;一个做平移动画的 View,触摸事件仍在原始位置响应。
源码目录:frameworks/base/core/java/android/view/animation/(共 29 个文件)
14.2.2 Animation 基类
抽象类 Animation(1363 行)定义动画生命周期:
// frameworks/base/core/java/android/view/animation/Animation.java,第40‑98行 public abstract class Animation implements Cloneable { public static final int INFINITE = -1; public static final int RESTART = 1; public static final int REVERSE = 2; public static final int START_ON_FIRST_FRAME = -1; public static final int ABSOLUTE = 0; public static final int RELATIVE_TO_SELF = 1; public static final int RELATIVE_TO_PARENT = 2; public static final int ZORDER_NORMAL = 0; public static final int ZORDER_TOP = 1; public static final int ZORDER_BOTTOM = -1; ... }核心内部状态(第 110‑237 行)
| 字段 | 类型 | 用途 |
|---|---|---|
| mEnded | boolean | getTransformation () 在动画结束时置位 |
| mStarted | boolean | 第一帧时置位 |
| mCycleFlip | boolean | REVERSE 重复模式下切换状态 |
| mInitialized | boolean | 播放前必须为 true |
| mFillBefore | boolean | 动画开始前应用变换(默认 true) |
| mFillAfter | boolean | 动画结束后保持变换 |
| mStartTime | long | 绝对起始时间,单位毫秒 |
| mDuration | long | 单次周期时长 |
| mRepeatCount | int | 重复次数(0 = 播放一次) |
| mRepeatMode | int | RESTART 或 REVERSE |
| mInterpolator | Interpolator | 缓动曲线 |
| mScaleFactor | float | 锚点缩放系数 |
生命周期由getTransformation(long, Transformation)驱动:计算流逝时间、应用插值器,调用抽象方法applyTransformation(float interpolatedTime, Transformation t)。
14.2.3 Transformation
Transformation 类(32‑80 行)封装视图动画输出结果:
// frameworks/base/core/java/android/view/animation/Transformation.java,第32‑48行 public class Transformation { public static final int TYPE_IDENTITY = 0x0; public static final int TYPE_ALPHA = 0x1; public static final int TYPE_MATRIX = 0x2; public static final int TYPE_BOTH = TYPE_ALPHA | TYPE_MATRIX; protected Matrix mMatrix; protected float mAlpha; protected int mTransformationType; ... }Transformation 持有 Matrix(平移 / 旋转 / 缩放)与 alpha 透明度。compose(Transformation)方法将两个变换拼接,AnimationSet 就是依靠该接口组合子动画。
14.2.4 具体动画子类
AlphaAnimation
最简单动画,仅修改透明度分量:
// frameworks/base/core/java/android/view/animation/AlphaAnimation.java,第67‑70行 @Override protected void applyTransformation(float interpolatedTime, Transformation t) { final float alpha = mFromAlpha; t.setAlpha(alpha + ((mToAlpha - alpha) * interpolatedTime)); }willChangeTransformationMatrix()返回 false,代表不修改矩阵,仅做透明度混合。
TranslateAnimation
修改矩阵平移实现 View 移动:
// frameworks/base/core/java/android/view/animation/TranslateAnimation.java,第166‑176行 @Override protected void applyTransformation(float interpolatedTime, Transformation t) { float dx = mFromXDelta; float dy = mFromYDelta; if (mFromXDelta != mToXDelta) { dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime); } if (mFromYDelta != mToYDelta) { dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime); } t.getMatrix().setTranslate(dx, dy); }initialize () 解析数值类型:
- ABSOLUTE:直接使用像素值
- RELATIVE_TO_SELF:乘以 View 自身尺寸
- RELATIVE_TO_PARENT:乘以父容器尺寸
RotateAnimation
围绕可配置锚点旋转:
// frameworks/base/core/java/android/view/animation/RotateAnimation.java,第166‑175行 @Override protected void applyTransformation(float interpolatedTime, Transformation t) { float degrees = mFromDegrees + ((mToDegrees - mFromDegrees) * interpolatedTime); float scale = getScaleFactor(); if (mPivotX == 0.0f && mPivotY == 0.0f) { t.getMatrix().setRotate(degrees); } else { t.getMatrix().setRotate(degrees, mPivotX * scale, mPivotY * scale); } }ScaleAnimation
支持锚点的缩放动画,解析起止值(可以是小数或尺寸):
// frameworks/base/core/java/android/view/animation/ScaleAnimation.java,第241‑258行 @Override protected void applyTransformation(float interpolatedTime, Transformation t) { float sx = 1.0f; float sy = 1.0f; float scale = getScaleFactor(); if (mFromX != 1.0f || mToX != 1.0f) { sx = mFromX + ((mToX - mFromX) * interpolatedTime); } if (mFromY != 1.0f || mToY != 1.0f) { sy = mFromY + ((mToY - mFromY) * interpolatedTime); } if (mPivotX == 0 && mPivotY == 0) { t.getMatrix().setScale(sx, sy); } else { t.getMatrix().setScale(sx, sy, scale * mPivotX, scale * mPivotY); } }14.2.5 AnimationSet
AnimationSet(553 行)用于组合多个同时播放的动画。它的 getTransformation 逆序遍历子动画,调用 compose () 拼接变换:
// frameworks/base/core/java/android/view/animation/AnimationSet.java,第390‑423行 @Override public boolean getTransformation(long currentTime, Transformation t) { final int count = mAnimations.size(); final ArrayList<Animation> animations = mAnimations; final Transformation temp = mTempTransformation; boolean more = false; boolean started = false; boolean ended = true; t.clear(); for (int i = count - 1; i >= 0; --i) { final Animation a = animations.get(i); temp.clear(); more = a.getTransformation(currentTime, temp, getScaleFactor()) || more; t.compose(temp); started = started || a.hasStarted(); ended = a.hasEnded() && ended; } ... }duration、fillBefore、fillAfter、repeatMode 等属性可以通过属性标记向下传递给子动画(第 54‑61 行):
// AnimationSet.java,第54‑61行 private static final int PROPERTY_FILL_AFTER_MASK = 0x1; private static final int PROPERTY_FILL_BEFORE_MASK = 0x2; private static final int PROPERTY_REPEAT_MODE_MASK = 0x4; private static final int PROPERTY_START_OFFSET_MASK = 0x8; private static final int PROPERTY_SHARE_INTERPOLATOR_MASK = 0x10; private static final int PROPERTY_DURATION_MASK = 0x20; private static final int PROPERTY_MORPH_MATRIX_MASK = 0x40; private static final int PROPERTY_CHANGE_BOUNDS_MASK = 0x80;14.2.6 插值器
android.view.animation 包内置 12 种插值器:
| 插值器 | 公式 / 行为 | 典型用途 |
|---|---|---|
| AccelerateDecelerateInterpolator | cos((t+1)*PI)/2 + 0.5 | 默认;自然运动 |
| AccelerateInterpolator | t^(2*factor) | 退出动画 |
| DecelerateInterpolator | 1‑(1‑t)^(2*factor) | 进入动画 |
| LinearInterpolator | t | 匀速 |
| BounceInterpolator | 分段二次函数 | 末尾弹跳 |
| OvershootInterpolator | 三次过冲 | 类弹簧效果 |
| AnticipateInterpolator | 先回拉再射出 | 卡通蓄力效果 |
| AnticipateOvershootInterpolator | 蓄力 + 过冲组合 | 组合效果 |
| CycleInterpolator | sin(2PIcycles*t) | 抖动 / 摇摆 |
| PathInterpolator | 自定义贝塞尔 / SVG 路径 | Material 动效 |
| BackGestureInterpolator | 返回手势曲线 | 预测返回 |
| BaseInterpolator | 抽象基类 | 自定义实现 |
AccelerateDecelerateInterpolator 实现非常简洁:
// frameworks/base/core/java/android/view/animation/AccelerateDecelerateInterpolator.java,第39行 public float getInterpolation(float input) { return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; }14.2.7 PathInterpolator
API21 引入,用于 Material Design 动效。PathInterpolator 将一条从 (0,0) 到 (1,1) 的 Path 映射为插值曲线。路径被离散成 (x,y) 点对,输入 t 通过二分查找得到对应的 y 值。
// frameworks/base/core/java/android/view/animation/PathInterpolator.java,第207‑237行 @Override public float getInterpolation(float t) { if (t <= 0) return 0; else if (t >= 1) return 1; // 二分查找x区间 int startIndex = 0; int endIndex = mX.length - 1; while (endIndex - startIndex > 1) { int midIndex = (startIndex + endIndex) / 2; if (t < mX[midIndex]) { endIndex = midIndex; } else { startIndex = midIndex; } } float xRange = mX[endIndex] - mX[startIndex]; if (xRange == 0) return mY[startIndex]; float tInRange = t - mX[startIndex]; float fraction = tInRange / xRange; float startY = mY[startIndex]; float endY = mY[endIndex]; return startY + (fraction * (endY - startY)); }支持三种构造方式:
- 二次贝塞尔:
PathInterpolator(controlX, controlY),1 个控制点 - 三次贝塞尔:
PathInterpolator(cx1, cy1, cx2, cy2),2 个控制点 - SVG Path Data:XML 属性 pathData,由 PathParser 解析
所有插值器实现 NativeInterpolator,为 HWUI RenderThread 动画提供原生句柄。
14.2.8 视图动画类继承体系
14.2.9 视图动画局限性
- 不修改真实属性:仅做视觉变换。View 的 left、top、width、height 不变,点击检测使用原始边界。
- 仅作用于 View:无法对普通对象、非 View 属性做动画。
- 类型有限:只支持矩阵(平移 / 旋转 / 缩放)和透明度,没有颜色动画,不支持任意类型数值。
- 矩阵乘法组合:AnimationSet 依靠矩阵拼接,复杂多属性协同能力受限。
这些局限促使 API11 引入属性动画框架。
14.2.10 getTransformation () 核心循环
视图动画的核心是逐帧计算变换的 getTransformation (),完整算法(1011‑1079 行):
// frameworks/base/core/java/android/view/animation/Animation.java,第1011‑1079行 public boolean getTransformation(long currentTime, Transformation outTransformation) { if (mStartTime == -1) { mStartTime = currentTime; } final long startOffset = getStartOffset(); final long duration = mDuration; float normalizedTime; if (duration != 0) { normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) / (float) duration; } else { // 时长为0时时间阶跃变化 normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f; } final boolean expired = normalizedTime >= 1.0f || isCanceled(); mMore = !expired; if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f); if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) { if (!mStarted) { fireAnimationStart(); mStarted = true; ... } if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f); if (mCycleFlip) { normalizedTime = 1.0f - normalizedTime; } getTransformationAt(normalizedTime, outTransformation); } if (expired) { if (mRepeatCount == mRepeated || isCanceled()) { if (!mEnded) { mEnded = true; guard.close(); fireAnimationEnd(); } } else { if (mRepeatCount > 0) { mRepeated++; } if (mRepeatMode == REVERSE) { mCycleFlip = !mCycleFlip; } mStartTime = -1; mMore = true; fireAnimationRepeat(); } } ... return mMore; }算法步骤:
- 起始时间初始化:第一次调用将 mStartTime 置为 currentTime,实现 START_ON_FIRST_FRAME。
- 归一化时间计算:
normalizedTime = (currentTime‑startTime‑offset)/duration,得到单次周期进度 [0,1]。 - 过期判断:normalizedTime >=1.0 代表当前周期结束。
- Fill 钳位:mFillEnabled 开启时,将时间限制在 [0,1],防止外推。
- 周期翻转:REVERSE 模式每次重复切换 mCycleFlip,为 true 时时间取反:
1.0‑normalizedTime。 - 应用变换:getTransformationAt () 执行插值并调用子类 applyTransformation ()。
- 重复处理:动画过期但未耗尽重复次数,重置 mStartTime 为‑1,mMore 置 true,下一帧继续运行。
14.2.11 resolveSize:数值类型解析 ¶
resolveSize ()(1185 行)将动画数值依据类型转为像素:
// Animation.java,第1185‑1196行 protected float resolveSize(int type, float value, int size, int parentSize) { switch (type) { case ABSOLUTE: return value; case RELATIVE_TO_SELF: return size * value; case RELATIVE_TO_PARENT: return parentSize * value; default: return value; } }支持 XML 写法如android:fromXDelta="50%"(相对自身)、android:fromXDelta="50%p"(相对父容器)。
14.2.12 窗口管理器中的视图动画
窗口管理器内部也使用视图动画实现遗留窗口转场。WindowAnimationSpec 对 View 动画做封装,作用对象改为 SurfaceControl。动画 Transformation 矩阵转换为 SurfaceControl.Transaction 操作(setPosition、setMatrix、setAlpha)。
14.2.13 插值器原生桥接
所有内置插值器实现 NativeInterpolator,提供createNativeInterpolator()返回原生句柄。HWUI 使用该句柄,在 RenderThread 运行相同插值曲线,避免每一帧跨 JNI 调用。
// AccelerateDecelerateInterpolator.java,第43‑47行 /** @hide */ @Override public long createNativeInterpolator() { return NativeInterpolatorFactory.createAccelerateDecelerateInterpolator(); }frameworks/base/libs/hwui/Interpolator.cpp中原生实现与 Java 公式完全一致,保证 UI 线程与 RenderThread 动画视觉效果统一。
14.2.14 视图动画文件总览 ¶
表格
| 文件 | 行数 | 用途 |
|---|---|---|
| Animation.java | 1363 | 抽象基类 |
| AnimationSet.java | 553 | 并发动画组 |
| AnimationUtils.java | ~400 | 加载工具、currentAnimationTimeMillis |
| Transformation.java | ~220 | 矩阵 + 透明度容器 |
| AlphaAnimation.java | 89 | 透明度动画 |
| TranslateAnimation.java | 241 | 位移动画 |
| RotateAnimation.java | 183 | 旋转动画 |
| ScaleAnimation.java | 289 | 缩放动画 |
| ClipRectAnimation.java | ~80 | 裁剪矩形动画 |
| ExtendAnimation.java | ~60 | 边缘扩展动画 |
| TranslateXAnimation.java | ~40 | X 轴平移(优化) |
| TranslateYAnimation.java | ~40 | Y 轴平移(优化) |
| PathInterpolator.java | 245 | 贝塞尔 / 路径插值 |
| AccelerateDecelerateInterpolator.java | 48 | 默认余弦缓动 |
| AccelerateInterpolator.java | ~55 | 幂曲线加速 |
| DecelerateInterpolator.java | ~55 | 幂曲线减速 |
| LinearInterpolator.java | ~35 | 线性 |
| BounceInterpolator.java | ~50 | 末尾弹跳 |
| OvershootInterpolator.java | ~60 | 三次过冲 |
| AnticipateInterpolator.java | ~55 | 运动前蓄力 |
| AnticipateOvershootInterpolator.java | ~70 | 蓄力 + 过冲组合 |
| CycleInterpolator.java | ~45 | 正弦周期 |
| BackGestureInterpolator.java | ~60 | 返回手势曲线 |
| BaseInterpolator.java | ~30 | 插值器抽象基类 |
| Interpolator.java | ~10 | 继承 TimeInterpolator 的接口 |
| LayoutAnimationController.java | ~350 | 子 View 错峰动画 |
| GridLayoutAnimationController.java | ~200 | 网格错峰动画 |
14.3 属性动画
14.3.1 概述
Android3.0(API11)引入属性动画,是 Android 现代动画主力。它修改任意 Java 对象真实属性,不只限于 View。当执行 View.setTranslationX 动画时,属性真实发生改变,点击检测、布局、无障碍均跟随动画状态。
源码目录:frameworks/base/core/java/android/animation/(31 个文件,~13400 行)
14.3.2 核心类继承体系
14.3.3 ValueAnimator 深度解析
ValueAnimator.java(1776 行)是属性动画的引擎。
关键字段(96‑279 行)
// frameworks/base/core/java/android/animation/ValueAnimator.java private static float sDurationScale = 1.0f; // 系统全局缩放系数(96行) long mStartTime = -1; // 第一帧时间(113行) float mSeekFraction = -1; // 跳转播放位置(119行) private long mDuration = 300; // 默认300ms(202行) private int mRepeatCount = 0; // 默认播放一次(211行) private int mRepeatMode = RESTART; // RESTART 或 REVERSE(218行) private TimeInterpolator mInterpolator = sDefaultInterpolator; //(237行) PropertyValuesHolder[] mValues; // 被动画的属性数组(247行) HashMap<String, PropertyValuesHolder> mValuesMap; // 属性名‑PVH查找表注意:Android17 移除老版本
mStartTimeCommitted“卡顿补偿” 标记;每个动画器用于修正起始时间的 commit 回调已删除(见 §14.3.12)。
时长缩放:全局静态sDurationScale会乘以所有动画时长。开发者选项 “动画器时长缩放” 修改该值。等于 0 时areAnimatorsEnabled()返回 false。
// ValueAnimator.java,394‑396行 public static boolean areAnimatorsEnabled() { return !(sDurationScale == 0); }工厂方法(417‑515 行)
| 工厂方法 | 求值器 | 说明 |
|---|---|---|
| ofInt(int...) | IntEvaluator | 整数区间 |
| ofFloat(float...) | FloatEvaluator | 浮点数区间 |
| ofArgb(int...) | ArgbEvaluator | sRGB 颜色插值 |
| ofObject(TypeEvaluator, Object...) | 自定义 | 任意类型 |
| ofPropertyValuesHolder(PVH...) | 按每个 Holder | 多属性同时动画 |
14.3.4 动画帧循环
调用 start (),ValueAnimator 将自身注册到 AnimationHandler,作为 AnimationFrameCallback。Handler 调度 Choreographer 帧回调。每次 VSYNC 到来:
animateBasedOnTime () 核心时序逻辑(简化):
- 计算
currentIterationFraction = (currentTime‑startTime)/duration - 处理重复:除以总迭代次数得到 overallFraction
- REVERSE 模式:奇数迭代翻转 fraction
- 调用 animateValue (fraction),应用插值器
14.3.5 ObjectAnimator
ObjectAnimator(1004 行)继承 ValueAnimator,将动画数值直接设置给目标对象。两种解析目标属性的方式:
- 属性名字符串:反射查找 setFoo () /getFoo ();float、int 返回类型存在优化 JNI 路径。
- Property 对象:使用 Property<T,V> 抽象,完全避开反射。
// frameworks/base/core/java/android/animation/ObjectAnimator.java,69‑80行 public final class ObjectAnimator extends ValueAnimator { private Object mTarget; private String mPropertyName; private Property mProperty; private boolean mAutoCancel = false; ... }常用工厂:
ObjectAnimator.ofFloat(view, "translationX", 0f, 100f) ObjectAnimator.ofFloat(view, View.TRANSLATION_X, 0f, 100f) // 推荐,无反射 ObjectAnimator.ofArgb(view, "backgroundColor", Color.RED, Color.BLUE)14.3.6 PropertyValuesHolder
PropertyValuesHolder(1729 行)封装单个被动画属性:属性名 / Property 引用、setter/getter、关键帧集合、类型求值器。
// frameworks/base/core/java/android/animation/PropertyValuesHolder.java,38‑78行 public class PropertyValuesHolder implements Cloneable { String mPropertyName; protected Property mProperty; Method mSetter = null; private Method mGetter = null; Class mValueType; Keyframes mKeyframes = null; ... }内部维护每个 Class 的 setter/getter 静态缓存,避免重复反射:
// PropertyValuesHolder.java,92‑97行 private static Class[] FLOAT_VARIANTS = {float.class, Float.class, double.class, int.class, Double.class, Integer.class}; private static Class[] INTEGER_VARIANTS = {int.class, Integer.class, float.class, double.class, Float.class, Double.class};14.3.7 Keyframes 与 TypeEvaluators
Keyframe 定义某个进度点(0.0‑1.0)对应的数值。KeyframeSet 保存有序 Keyframe 集合,在相邻关键帧之间插值。
内置求值器:
| 求值器 | 运算 |
|---|---|
| IntEvaluator | startValue + (int)(fraction * (endValue‑startValue)) |
| FloatEvaluator | startValue + fraction * (endValue‑startValue) |
| ArgbEvaluator | sRGB 色彩空间按通道插值 |
| PointFEvaluator | PointF 的 x、y 独立插值 |
| RectEvaluator | Rect left/top/right/bottom 插值 |
| IntArrayEvaluator | int 数组逐元素插值 |
| FloatArrayEvaluator | float 数组逐元素插值 |
14.3.8 AnimatorSet 与依赖图
AnimatorSet(2280 行)用内部 Node 结构,把多个 Animator 组织成一张依赖关系图。
Builder API 构建依赖链:
AnimatorSet set = new AnimatorSet(); set.play(fadeIn).before(moveRight); set.play(fadeIn).before(scaleUp); set.play(moveRight).before(colorChange); set.play(scaleUp).before(colorChange);内部维护按时间排序的 AnimationEvent 列表。每一帧,处理时间已到达的事件,启动或结束子动画器。
14.3.9 AnimationHandler 与后台暂停
AnimationHandler(515 行)管理线程内动画循环。
关键机制 ——后台暂停(271‑287 行):当进程全部窗口切后台,AnimationHandler 暂停所有无限时长动画,节省 CPU。通过 mAnimatorRequestors 跟踪可见状态。
// frameworks/base/core/java/android/animation/AnimationHandler.java,271‑287行 private Choreographer.FrameCallback mPauser = frameTimeNanos -> { if (mAnimatorRequestors.size() > 0) { return; // 调度之后有组件重新启用动画 } for (int i = 0; i < mAnimationCallbacks.size(); ++i) { AnimationFrameCallback callback = mAnimationC