SystemUI 动画技术全景调研

调研范围:packages/SystemUI/ 全目录(含 AOSP 层 + MIUI 定制层) 调研时间:2026-04-28 代码分支:dev-2604-26q2


目录


一、总览

SystemUI 中共使用 15+ 大类 动画技术,三套体系并存:

体系代表技术定位
AOSP 原生属性动画ValueAnimator / ObjectAnimator / AnimatorSet最基础、最通用,贯穿全模块
小米 Folme 物理动画miuix.animation.FolmeMIUI 差异化交互核心,仅 MIUI 层使用
Jetpack Compose 动画animateXAsState / AnimatedVisibility / Animatable新 UI 层主力,配合自研 SceneTransitionLayout

各类型渗透度排名

排名动画类型文件数说明
1ValueAnimator177最基础的数值驱动器
2Jetpack Compose Animation177新 Compose UI 层主力
3Folme(小米自研)151MIUI 交互动效核心
4ViewPropertyAnimator136(调用次)简洁链式 View 动画
5Canvas/invalidate 自绘105高度定制的绘制动画
6Blur/RenderEffect102+79视觉氛围/高斯模糊
7Transition Framework87布局切换场景
8Scroller/OverScroller78弹性滚动引擎
9ObjectAnimator78精确属性控制
10AnimatorSet71多动画编排
11SpringAnimation (AndroidX)51物理弹性动画
12Window/Activity 转场42窗口/页面过渡
13ViewFlipper/ViewSwitcher36子 View 切换
14MotionLayout34约束布局过渡
15AnimatedVectorDrawable269(XML)图标形变
16Lottie24AE 导出复杂动画
17FlingAnimation19惯性滑动
18Ripple/涟漪19生物识别涟漪
19PhysicsAnimator7AOSP 内部物理引擎

二、Folme 动画(小米自研物理动画框架)

2.1 概述

Folme 是小米 miuix SDK 自研的物理动画框架,基于弹簧物理模型,提供状态机驱动的声明式动画 API。在 MIUI 层使用最广泛(151 个文件),但在 AOSP 层零使用。

2.2 核心 API 入口

入口调用次数说明
Folme.useAt(view)688主入口,绑定到 View 返回 IFolme
Folme.useValue(object)217值动画,驱动非 View 的 float 属性
Folme.use(view)74备选 View 入口
Folme.state()73静态状态访问
Folme.clean(target)28清理资源(onDetachedFromWindow 中调用)
Folme.to(...)23静态快捷方法
Folme.afterFrictionValue(...)13摩擦力物理计算
Folme.cancel(...)11取消运行中的动画
Folme.visible()8可见性动画
Folme.setTo(...)6立即设置(无动画)

2.3 子 API 链

链式调用使用次数说明
.state()641状态机驱动动画(主导模式
.touch()12触摸反馈(按压缩放/着色)
.visible()~12显隐动画
.hover()2悬浮效果

2.4 缓动曲线分布

缓动类型引用次数说明
SPRING_PHY285物理弹簧(绝对主导
FolmeEase.spring(damping, stiffness)108弹簧快捷方式
DECELERATE23减速曲线
FolmeEase.sinOut(duration)13正弦缓出
SIN_OUT7正弦缓出(旧写法)
FolmeEase.cubicOut(duration)4三次缓出
其他(sinInOut/quartOut/bezier/linear 等)各 1-2少量使用

结论:Folme 几乎全部使用弹簧物理缓动,SPRING_PHY + FolmeEase.spring 合计占比 >85%。

2.5 常用动画属性

属性引用次数说明
ViewProperty.ALPHA376最常用
ViewProperty.TRANSLATION_Y256纵向位移
ViewProperty.SCALE_Y193纵向缩放(通常与 SCALE_X 成对)
ViewProperty.SCALE_X188横向缩放
ViewProperty.TRANSLATION_X154横向位移
ViewProperty.Y80绝对 Y 位置
ViewProperty.X32绝对 X 位置
ViewProperty.ROTATION16Z 轴旋转
ViewProperty.TRANSITION_ALPHA16过渡专用 alpha
ViewProperty.HEIGHT6高度
ViewProperty.ROTATION_X5X 轴旋转(3D 翻转)
ViewProperty.Z5Z 轴高度

2.6 模块分布

模块文件数
miuiModules/Keyguard38
miui/Notification25
miui/Flip24
miui/Keyguard15
miui/QuickSetting9
miui/StatusBar8
miuiModules/Notification8
miuiModules/StatusBar5
miuiModules/miuiutils4
miuiModules/Base4
miuiModules/MiuiBiometrics2
miuiModules/ControlCenter2
其他(QuickAppPanel/MiuiCharge)2
AOSP 层(src/)0

2.7 典型代码模式

模式一:AnimState 常量定义 + AnimConfig 配置

// FolmeAnimState.java (ControlCenter)
AnimState mShowAnim = new AnimState("control_center_detail_show")
    .add(ViewProperty.ALPHA, 1f);
AnimState mHideAnim = new AnimState("control_center_detail_hide")
    .add(ViewProperty.ALPHA, 0f);
AnimConfig mAnimConfig = new AnimConfig()
    .setEase(EaseManager.getStyle(EaseManager.EaseStyleDef.SPRING, 300L, 0.99f, 0.6666f));
 
// 下拉控制中心面板
AnimState mPanelShowAnim = new AnimState("control_panel_show")
    .add(ViewProperty.ALPHA, 1f)
    .add(ViewProperty.SCALE_X, 1f)
    .add(ViewProperty.SCALE_Y, 1f);
AnimState mPanelHideAnim = new AnimState("control_panel_hide")
    .add(ViewProperty.ALPHA, 0f)
    .add(ViewProperty.SCALE_X, 0.8f)
    .add(ViewProperty.SCALE_Y, 0.8f);

模式二:Per-Property 差异化缓动(AnimSpecialConfig)

// FlipRowAnimationUtils.kt — 每个属性使用不同弹簧参数
val scaleXYCon = AnimSpecialConfig()
    .setEase(EaseManager.EaseStyleDef.SPRING_PHY, 0.95f, 0.25f)
    .setDelay(50) as AnimSpecialConfig
val yCon = AnimSpecialConfig()
    .setEase(EaseManager.EaseStyleDef.SPRING_PHY, 0.98f, 0.45f) as AnimSpecialConfig
val alphaCon = AnimSpecialConfig()
    .setEase(EaseManager.EaseStyleDef.SPRING_PHY, 0.98f, 0.35f) as AnimSpecialConfig
 
notificationAnimConfig = AnimConfig()
    .setSpecial(ViewProperty.SCALE_X, scaleXYCon)
    .setSpecial(ViewProperty.SCALE_Y, scaleXYCon)
    .setSpecial(ViewProperty.TRANSLATION_Y, yCon)
    .setSpecial(ViewProperty.ALPHA, alphaCon)
    .setDelay((index * 50 + 80).toLong())

模式三:Folme.useValue — 值动画(非 View)

// NotificationPanelExpansionAnimator.kt
class NotificationPanelExpansionAnimator @Inject constructor() :
    FloatFlowProperty("notif_expansion", 0.001f), LifecycleOwner {
 
    internal val expansion = MutableStateFlow(0f)
    private val animator = Folme.useValue(expansion)
    private val animConfig = AnimConfig()
        .setEase(EaseManager.EaseStyleDef.SPRING_PHY, 0.9f, 0.35f)
        .addListeners(object : TransitionListener() { ... })
        .enableStartImmediately(true)
 
    internal fun updateExpansion(ratio: Float, animate: Boolean = true) {
        if (animate) animator.to(this, ratio, animConfig)
        else animator.setTo(this, ratio, animConfig)
    }
}

模式四:Touch 触摸反馈

// NumPadKey.kt — 密码键盘按键
protected fun updateDrawableState() {
    if (mLastPressedState) {
        Folme.use(this).resetTo(mPressedFrom).to(mPressedTo, CONFIG_PRESSED)
    } else {
        Folme.use(this).to(mReleased, CONFIG_RELEASE)
    }
}
 
override fun onDetachedFromWindow() {
    super.onDetachedFromWindow()
    Folme.clean(this)  // 必须清理防止泄漏
}

模式五:复杂状态机(通知 AOD 动画)

// MiuiNotificationAnimationExtensions.kt
if (!isWakingUp) {
    if (shadeChangeToKeyguard) {
        Folme.use(view).setTo(notificationKeyguardState)
            .to(notificationAodState, notificationAnimToAodConfig)
    } else {
        Folme.use(view).to(notificationAodState, notificationAnimToAodConfig)
    }
} else {
    if (view.viewState.mInjector?.animatingToAod == true) {
        Folme.use(view).cancel("wakeup_aod")
        Folme.use(view).to(notificationKeyguardState, notificationAnimWakeUpConfig)
    } else {
        Folme.use(view).setTo(notificationInitState, AnimConfig().addListeners(...))
    }
}

2.8 完整 API 清单

miuix.animation.Folme                          // 主入口
miuix.animation.FolmeEase                       // 缓动快捷方法
miuix.animation.FolmeObject                     // 对象动画
miuix.animation.IFolme                          // 接口
miuix.animation.IStateStyle                     // 状态样式接口
miuix.animation.ITouchStyle                     // 触摸样式接口
miuix.animation.IHoverStyle                     // 悬浮样式接口
miuix.animation.IAnimTarget                     // 动画目标接口
miuix.animation.ValueTarget                     // 值目标
miuix.animation.ViewTarget                      // View 目标
miuix.animation.base.AnimConfig                 // 动画配置
miuix.animation.base.AnimSpecialConfig          // 属性级特殊配置
miuix.animation.controller.AnimState            // 动画状态定义
miuix.animation.controller.IFolmeStateStyle     // 状态样式控制器
miuix.animation.listener.TransitionListener     // 过渡监听器
miuix.animation.listener.UpdateInfo             // 更新信息
miuix.animation.property.FloatProperty          // 浮点属性
miuix.animation.property.ValueProperty          // 值属性
miuix.animation.property.ViewProperty           // View 属性枚举
miuix.animation.utils.EaseManager               // 缓动管理器
miuix.animation.utils.EaseManager.EaseStyle     // 缓动样式
miuix.animation.utils.EaseManager.EaseStyleDef  // 缓动样式定义
miuix.animation.physics.DynamicAnimation        // 动态动画

三、ValueAnimator

3.1 概述

指标数值
使用文件数177
import/调用行数470

ValueAnimator 是 SystemUI 中使用面最广的基础动画 API,作为”数值驱动器”驱动各种属性变化。

3.2 主要使用模式

模式一:0→1 进度驱动器(最常见)

// ScrimController.java:1487
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.addUpdateListener(animation -> {
    float animAmount = (float) animation.getAnimatedValue();
    float alpha = MathUtils.lerp(startAlpha, finalScrimAlpha, animAmount);
    int tint = ColorUtils.blendARGB(initialScrimTint, finalScrimTint, animAmount);
    updateScrimColor(scrim, alpha, tint);
});
anim.setInterpolator(mInterpolator);
anim.setDuration(mAnimationDuration);

这是 SystemUI 中最普遍的惯用法:用 0→1 的归一化进度值,在 UpdateListener 中手动计算派生值(alpha、tint、position 等)。一个 Animator 驱动多个属性。

模式二:直接数值应用

ValueAnimator.ofInt(child.actualHeight, child.collapsedHeight).apply {
    addUpdateListener { animation ->
        child.actualHeight = animation.animatedValue as Int
    }
}

模式三:颜色过渡

// ColorSchemeTransition.kt:86
open fun buildAnimator(): ValueAnimator {
    val animator = ValueAnimator.ofFloat(0f, 1f)
    animator.duration = 333
    animator.addUpdateListener(this)
    return animator
}

3.3 常用时长

时长 (ms)出现次数典型场景
25046标准过渡
20044快速过渡
30031中等过渡
10029快速/细微动画
15024快速淡入淡出
50023长/强调动画
100017缓慢/审慎动画
45012复杂过渡
1677~10帧@60fps

200-300ms 是最常用的时长区间,占比最高。

3.4 常配合的 Interpolator

Interpolator使用次数场景
Interpolators.LINEAR87透明度渐变、匀速变化
PathInterpolator(自定义曲线)66精调运动曲线
Interpolators.FAST_OUT_SLOW_IN47Material Design 标准
DecelerateInterpolator37进入动画
AccelerateInterpolator31退出动画
Interpolators.ALPHA_OUT28淡出
Interpolators.ALPHA_IN26淡入
Interpolators.LINEAR_OUT_SLOW_IN25减速曲线
Interpolators.EMPHASIZED13Material 3 强调
Interpolators.DECELERATE_QUINT7重度减速

3.5 模块分布(Top 10)

目录文件数
keyguard/domain/interactor11
statusbar/9
com/android/keyguard/8
statusbar/notification/row6
miui/Keyguard/5
animation/5
statusbar/phone4
statusbar/notification/stack4

四、ObjectAnimator

4.1 概述

指标数值
使用文件数78
调用次数168

ObjectAnimator 直接指定目标对象 + 属性名进行动画。

4.2 最常动画的属性

属性次数说明
"alpha" / View.ALPHA53最多
"translationY" / View.TRANSLATION_Y11上下滑动
"translationX"7左右滑动
"scaleX" / "scaleY"10缩放(成对使用)
View.ROTATION4旋转
"textSize"3字号动画(充电动画)
"transitionAlpha"2过渡专用 alpha
"elevation"1阴影深度
View.TRANSLATION_Z1Z 轴平移

4.3 自定义 Property(~25+ 个)

SystemUI 定义了大量自定义 FloatProperty / IntProperty,使用 View tags 存储动画状态:

自定义 Property文件用途
ICON_APPEAR_AMOUNTStatusBarIconView.java图标出现状态
DOT_APPEAR_AMOUNTStatusBarIconView.java通知小圆点
TRANSLATE_CONTENTExpandableNotificationRow.java滑动位移
notificationVisibilityNotificationWakeUpCoordinator.kt唤醒可见性
ABSOLUTE_X / ABSOLUTE_YAnimatableProperty.java布局安全的绝对定位
WIDTH / HEIGHTAnimatableProperty.java尺寸动画
KEY_DRAWABLE_ROTATEKeyButtonDrawable.java导航键旋转
mDozeAmountStatusBarStateControllerImpl.javaDoze 过渡
topRoundness / bottomRoundnessRoundable.kt通知圆角
fold_header_alpha / fold_header_trans_yFoldNotificationHeaderController.ktMIUI 折叠头部

4.4 典型代码

// StatusBarIconView.java:126 — 自定义 FloatProperty
private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT
    = new FloatProperty<StatusBarIconView>("iconAppearAmount") {
        @Override public void setValue(StatusBarIconView object, float value) {
            object.setIconAppearAmount(value);
        }
        @Override public Float get(StatusBarIconView object) {
            return object.getIconAppearAmount();
        }
    };
// 使用:
mIconAppearAnimator = ObjectAnimator.ofFloat(this, ICON_APPEAR_AMOUNT, 1.0f);
// WindowMagnificationController.java:1663 — PropertyValuesHolder 多属性
ObjectAnimator scaleAnimator = ObjectAnimator.ofPropertyValuesHolder(mMirrorView,
    PropertyValuesHolder.ofFloat(View.SCALE_X, 1, mBounceEffectAnimationScale, 1),
    PropertyValuesHolder.ofFloat(View.SCALE_Y, 1, mBounceEffectAnimationScale, 1));
scaleAnimator.setDuration(mBounceEffectDuration);
scaleAnimator.start();

五、AnimatorSet(动画编排)

5.1 概述

指标数值
使用文件数71

5.2 playTogether vs playSequentially

方式次数占比
playTogether()7988.8%
playSequentially()1011.2%

比例约 8:1,并行动画是常态,顺序动画仅用于明确的”先A后B”场景。

5.3 playSequentially 使用场景

全部 10 处均为”状态A → 状态B”的视觉序列:

  • FaceScanningOverlay.kt — cameraProtect 后 rimAppear
  • ControlViewHolder.kt — fadeOut 后 fadeIn
  • KeyguardIndicationTextView.java — fadeOut 后 fadeIn
  • AuthRippleView.kt — dwellPulseOut 后 expandDwell
  • PasswordTextView.java/kt — overshoot 后 settle
  • KeyguardPinBasedInputView.java/kt — scaleDown 后 scaleUp
  • LockPatternView.java — activation 后 deactivation

5.4 典型代码

// ToastDefaultAnimation.kt:41 — 入场动画编排
val sX = ObjectAnimator.ofFloat(view, "scaleX", 0.9f, 1f).apply {
    interpolator = scaleInterp; duration = 333
}
val sY = ObjectAnimator.ofFloat(view, "scaleY", 0.9f, 1f).apply {
    interpolator = scaleInterp; duration = 333
}
val vA = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f).apply {
    interpolator = linearInterp; duration = 66
}
val tA = ObjectAnimator.ofFloat(text, "alpha", 0f, 1f).apply {
    interpolator = linearInterp; duration = 283; startDelay = 50
}
return AnimatorSet().apply { playTogether(sX, sY, vA, tA, iA) }

六、ViewPropertyAnimator(view.animate())

6.1 概述

指标数值
调用次数138

最简洁的 View 动画 API,链式调用。

6.2 常用链式属性

属性次数
.alpha()13
.setDuration()5
.scaleX() / .scaleY()各 2
.translationX()1

6.3 模块分布(Top 10)

目录调用数
statusbar/19
statusbar/notification/row15
shade/7
miui/QuickSetting/customize7
miui/QuickSetting/qs6
miuiModules/Notification/utils6
selectiontoolbar/5
miui/StatusBar/pipeline5
miui/Flip/tinyPanel5

6.4 典型代码

// StackScrollerDecorView.java
view.animate().cancel();
view.animate()
    .alpha(endValue)
    .setInterpolator(interpolator)
    .setDuration(mAnimationDuration)
    .setListener(new AnimatorListenerAdapter() { ... });

七、SpringAnimation / DynamicAnimation(AndroidX 物理动画)

7.1 概述

指标数值
使用文件数40(非测试)

7.2 弹簧参数配置一览

位置StiffnessDamping Ratio场景
SwipeHelper550f0.52f滑动回弹
MediaCarouselScrollHandlerSTIFFNESS_LOWDAMPING_RATIO_LOW_BOUNCY滚动停靠(弹跳)
NotificationShadeDepthControllerSTIFFNESS_LOWDAMPING_RATIO_NO_BOUNCY模糊深度
NotificationShadeDepthController(唤醒)STIFFNESS_HIGHDAMPING_RATIO_NO_BOUNCY快速清除模糊
PhysicsPropertyAnimator380f1.3f(过阻尼)通知栈动画
MagneticNotificationRowManager(脱离)800f0.95f磁性脱离
MagneticNotificationRowManager(回弹)550f0.6f回弹
MagneticNotificationRowManager(吸附)850f0.95f磁性吸附

7.3 常用动画属性

属性引用次数
ALPHA38
TRANSLATION_X15
TRANSLATION_Y13
SCALE_X4
SCALE_Y4
ROTATION1

7.4 模块分布(Top 10)

目录引用数
accessibility/floatingmenu43
animation/lib23
statusbar/notification/stack19
navigationbar/gestural14
animation/src14
miui/Keyguard/screenfade13
miuiModules/StatusBar/animation12
unfold/progress11
volume/dialog10
miuiModules/Notification/media10

7.5 典型代码

// MagneticNotificationRowManagerImpl.kt:77
private val detachForce = SpringForce()
    .setStiffness(DETACH_STIFFNESS)      // 800f
    .setDampingRatio(DETACH_DAMPING_RATIO) // 0.95f
private val snapForce = SpringForce()
    .setStiffness(SNAP_BACK_STIFFNESS)     // 550f
    .setDampingRatio(SNAP_BACK_DAMPING_RATIO) // 0.6f
// NotificationShadeDepthController.kt:494
shadeAnimation.setStiffness(SpringForce.STIFFNESS_LOW)
shadeAnimation.setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)

八、FlingAnimation(惯性动画)

8.1 概述

指标数值
使用文件数11

8.2 使用场景

文件场景
ExpandHelper.java通知展开/折叠
SwipeHelper.java滑动删除
KeyguardAffordanceView.java锁屏快捷入口
BouncerSwipeTouchHandler.kt密码界面滑动
ShadeAnimationInteractor*.kt(4 文件)通知栏 fling
MenuAnimationController.java辅助功能浮动菜单
TinyKeyguardPanelViewControllerImpl.kt翻盖锁屏
FlingOnBackAnimationCallback.kt预测性返回手势

8.3 摩擦力参数

  • FLING_FRICTION = 6f — 返回手势(FlingOnBackAnimationCallback)
  • 动态传入 friction — 浮动菜单(MenuAnimationController)

8.4 典型代码

// FlingOnBackAnimationCallback.kt:121
FlingAnimation(FloatValueHolder())
    .setStartValue((lastBackEvent?.progress ?: 0f) * SCALE_FACTOR)
    .setFriction(FLING_FRICTION)
    .setStartVelocity(velocityTracker.xVelocity)
    .setMinValue(0f)
    .setMaxValue(SCALE_FACTOR)

九、PhysicsAnimator(AOSP SystemUI 自研)

9.1 概述

指标数值
使用文件数5

AOSP SystemUI 内部封装,支持在一个 API 中混合弹簧和 fling。

9.2 使用位置

文件场景
SwipeHelper.java通知滑动回弹
MediaCarouselScrollHandler.kt媒体轮播滚动/fling
ExpandableNotificationRow.java取消物理动画
DragToInteractView.kt气泡拖拽交互
MiuiQSContainer.ktMIUI 快设容器

9.3 典型代码

// MediaCarouselScrollHandler.kt:333
PhysicsAnimator.getInstance(this)
    .spring(
        CONTENT_TRANSLATION,
        newTranslation,
        startVelocity = 0.0f,
        config = translationConfig,
    )
    .start()

十、Jetpack Compose Animation

10.1 概述

指标数值
使用文件数177
导入 compose.animation 的文件160

Compose 声明式动画是新 UI 层的主力,覆盖锁屏、通知、快设、音量面板等核心场景。

10.2 API 使用分布

状态驱动动画(animateXAsState)

API使用次数代表文件
animateFloatAsState45ActionList.kt, CommunalHub.kt, ShadeScene.kt, PinBouncer.kt
animateColorAsState16PinBouncer.kt, PlatformSlider.kt
animateDpAsState15ColumnVolumeSliders.kt, PinBouncer.kt
animateIntAsState1NavBarPill.kt

高级 Composable 动画

API使用次数代表文件
AnimatedVisibility69CommunalHub.kt(7), Media.kt(6), ColumnVolumeSliders.kt(3)
AnimatedContent24QuickSettingsShadeOverlay.kt, FooterActions.kt, Toolbar.kt
Crossfade7Media.kt(专辑封面切换), AlternateBouncer.kt
updateTransition~8ResizeableItemFrame.kt, Selection.kt, EditTile.kt
rememberInfiniteTransition1CommunalContainer.kt(背景渐变)
MutableTransitionState~12AlternateBouncer.kt, NavBarPill.kt

底层/手动控制动画

API使用次数代表文件
Animatable(创建)51PatternBouncer.kt(5), PinBouncer.kt, ShadeHeader.kt, NavBarPill.kt
animateTo / snapTo 调用~299广泛分布
animateContentSize13VolumeSlider.kt, Media.kt(4), EditTile.kt
LaunchedEffect(总计)~243动画相关子集驱动 Animatable 协程

AnimationSpec 类型

Spec使用次数常见参数
tween()187150-500ms, CubicBezierEasing, Easings.StandardAccelerate
spring()~69StiffnessMediumLow, StiffnessHigh, DampingRatioNoBouncy
snap()13零时长立即切换
keyframes4NavBarPill.kt, BounceableTileViewModel.kt

tween 占绝对主导(187 vs 69 spring),Compose 层更偏好基于时长的动画而非物理弹簧。

10.3 SceneTransitionLayout(自研场景过渡框架)

SystemUI 构建了自研的 SceneTransitionLayout 系统(compose/scene/),拥有 40 个场景过渡定义文件compose/features/.../transitions/)。使用 TransitionBuilder DSL:

// FromLockscreenToGoneTransition.kt
fun TransitionBuilder.lockscreenToGoneTransition() {
    spec = tween(durationMillis = 500)
    fractionRange(end = 0.3f, easing = Easings.PredictiveBack) {
        fade(LockscreenElementKeys.Region.Upper)
        fade(LockscreenElementKeys.LockIcon)
        translate(LockscreenElementKeys.Region.Upper, y = (-48).dp)
        translate(LockscreenElementKeys.Notifications.Stack, y = (-72).dp)
    }
}

这是锁屏↔通知栏↔快设等场景间过渡的主要动画机制,不使用标准的 AnimatedContent

10.4 模块分布

功能区域文件数
Scene transitions(框架+定义)63
Keyguard/Lockscreen/Bouncer16
Screen Capture/Recording13
Quick Settings11
Volume Panel9
Communal Hub8
Ambient Cue5
Notifications4
Shade3
Media Player3

10.5 典型代码

Animatable + LaunchedEffect 弹跳动画

// ShadeHeader.kt:866 — 循环弹跳
val animatable = remember { Animatable(0f) }
LaunchedEffect(isEnabled) {
    if (isEnabled) {
        while (true) {
            animatable.animateTo(
                targetValue = with(density) { -(10.dp).toPx() },
                animationSpec = tween(200, easing = CubicBezierEasing(0.15f, 0f, 0.23f, 1f)))
            animatable.animateTo(0f,
                tween(167, easing = CubicBezierEasing(0.74f, 0f, 0.22f, 1f)))
            animatable.animateTo(
                with(density) { -(5.dp).toPx() },
                tween(150, easing = CubicBezierEasing(0.62f, 0f, 0.35f, 1f)))
            animatable.animateTo(0f,
                tween(117, easing = CubicBezierEasing(0.67f, 0f, 0.51f, 1f)))
            delay(1000)
        }
    }
}

PatternBouncer — 多 Animatable 映射

// PatternBouncer.kt:117
val dotScalingAnimatables = remember(dots) { dots.associateWith { Animatable(1f) } }
val lineFadeOutAnimatables = remember(dots) { dots.associateWith { Animatable(1f) } }
 
LaunchedEffect(currentDot, isAnimationEnabled) {
    dotScalingAnimatables.entries.forEach { (dot, animatable) ->
        scope.launch {
            if (dot == currentDot) {
                animatable.animateTo(SELECTED_DOT_DIAMETER_DP / DOT_DIAMETER_DP.toFloat(),
                    tween(easing = Easings.StandardAccelerate))
            } else {
                animatable.animateTo(1f, tween(easing = Easings.StandardDecelerate))
            }
        }
    }
}

Crossfade 媒体封面切换

// Media.kt:946
Crossfade(targetState = image, modifier = modifier) { imageOrNull ->
    val backgroundImage = imageOrNull?.let { (it as Icon.Loaded).asImageBitmap() }
    if (backgroundImage != null) {
        Image(bitmap = backgroundImage, contentScale = ContentScale.Crop,
            modifier = Modifier.fillMaxSize().drawWithContent {
                drawContent()
                drawRect(brush = Brush.radialGradient(...))
            })
    }
}

rememberInfiniteTransition — 无限循环渐变

// CommunalContainer.kt:447
val infiniteTransition = rememberInfiniteTransition()
val centerFraction by infiniteTransition.animateFloat(
    initialValue = 0f, targetValue = 1f,
    animationSpec = infiniteRepeatable(
        animation = tween(ANIMATION_DURATION_MS,
            easing = CubicBezierEasing(0.33f, 0f, 0.67f, 1f)),
        repeatMode = RepeatMode.Reverse,
    ))

十一、Transition Framework(场景切换)

11.1 概述

指标数值
使用文件数87
TransitionManager.beginDelayedTransition 调用13

11.2 Transition 类型使用

类型实例化次数文件
TransitionSet6NotificationInfo, BaseBlueprintTransition, ClockSizeTransition
Fade(OUT + IN)4NotificationInfo, NotificationConversationInfo
ChangeBounds3NotificationInfo, BaseBlueprintTransition
AutoTransition3ChannelEditorListView, BiometricViewSizeBinder, KeyguardClockViewBinder
Explode0未使用
Slide0未使用

11.3 LayoutTransition

文件场景
BatteryMeterView.java电池图标显隐
NavigationBarView.java导航栏按钮变化

11.4 常见模式

// NotificationInfo.java — TransitionSet 组合
TransitionSet transitionSet = new TransitionSet();
transitionSet.setOrdering(TransitionSet.ORDERING_TOGETHER);
transitionSet.addTransition(new Fade(Fade.OUT))
    .addTransition(new ChangeBounds())
    .addTransition(new Fade(Fade.IN));
TransitionManager.beginDelayedTransition(this, transitionSet);

十二、MotionLayout

12.1 概述

指标数值
使用文件数(含 XML)26

12.2 功能分布

功能文件
锁屏 PIN/图案/密码输入布局keyguard_pin_motion_layout.xml, keyguard_pattern_motion_layout.xml, keyguard_password_motion_layout.xml + 对应 MotionScene
QS 头部折叠/展开combined_qs_header.xml, combined_qs_header_scene.xml
音量面板铃声模式抽屉volume_dialog_top_section.xml, volume_dialog_ringer_drawer_motion_scene.xml

12.3 关键文件

Java/Kotlin: ShadeHeaderController.kt, QsBatteryModeController.kt, VolumeDialogRingerViewBinder.kt, KeyguardPasswordView.kt, KeyguardPatternView.kt, KeyguardPINView.kt, NoRemeasureMotionLayout.kt


十三、Lottie

13.1 概述

指标数值
使用文件数26
JSON 动画资源文件71

13.2 功能分布

功能区域文件数JSON 资源数说明
生物识别(指纹/面部)7~30指纹→错误、错误→成功、认证中等状态切换
触摸板手势教程48返回/Home/最近/切换 教学动画
功能键教程42Action Key 教学+成功
锁屏设备入口12UDFPS AOD/锁屏指纹
音量面板23audio_bars_in/playing/out
截屏1截屏架动画
后置显示12折叠/翻转提示
MIUI 通知2抬头通知、设备通知

13.3 JSON 资源分类

分类文件数代表文件
SFPS 侧面指纹~30sfps_fp_to_error_*.json(0/90/180/270度旋转变体)
面部对话框6face_dialog_authenticating.json, face_dialog_dark_to_checkmark.json
指纹对话框7fingerprint_dialog_fp_to_error.json
触摸板教程8back_gesture_edu.json, home_gesture_success.json
音量音频条3audio_bars_in.json, audio_bars_playing.json
UDFPS2udfps_aod_fp.json, udfps_lockscreen_fp.json

十四、传统 View Animation(Tween/Frame)

14.1 概述

指标数值
代码引用行数331
XML anim 资源文件71

14.2 XML 动画类型分布

类型文件数
<set>(组合)35
<translate>6
<objectAnimator>5
<alpha>4

14.3 常用时长

时长 (ms)出现次数说明
8362~5帧@60fps,锁屏图标状态切换
10042快速切换
13336~8帧
18328略慢
11728~7帧
25022标准过渡
16718~10帧

14.4 MIUI 特有 XML 动画

模块文件场景
miui/Notificationdialog_bottom_in.xml, dialog_bottom_out.xml底部弹窗进出
miui/StatusBarspring_phy.xml, translate_enter/exit.xml弹簧动画/平移进出
miui/Keyguardshrink_to_bottom.xml, stretch_from_bottom.xml收缩/展开动画
miui/Keyguardkeyguard_face_unlock_error_*_rotate.xml面部解锁错误旋转

十五、AnimatedVectorDrawable(矢量动画)

15.1 概述

指标数值
AVD XML 文件数257
代码引用文件数30

15.2 动画图标分类

分类代表文件说明
QS 磁贴图标qs_bluetooth_icon_off/on, qs_hotspot_icon_off开关状态切换动画
锁图标状态lock_lock.xml, lock_unlock.xml, lock_to_error.xml锁→解锁→错误
设备控制图标ic_device_outlet_off_anim.xml, ic_device_lock_on_anim.xmlIoT 设备状态
PIN 密码点pin_dot_avd.xml, bouncer_shape_*.xml密码输入动画
媒体播放ic_media_pause_button.xml暂停按钮
旋转按钮ic_sysbar_rotate_button_ccw_start_*.xml屏幕旋转
进度指示器progress_indeterminate_horizontal_material_trimmed.xml不确定进度条
勿扰模式avd_dnd_to_on.xmlDnD 开关

十六、模糊/RenderEffect 动画

16.1 概述

技术文件数说明
MiBlurCompat(MIUI 私有)57MIUI 专属高性能模糊
标准 RenderEffect22Android 12+ 标准 API
BlurUtils102(含引用)SystemUI 模糊工具类

比例约 2.6:1,MiBlurCompat 占主导。

16.2 MiBlurCompat API

setMiBackgroundBlurRadiusCompat(radius)
setMiViewBlurModeCompat(mode)  // DRAW_RECT_AND_BLEND, CLEAR_BLUR, SAVE_LAYER...
addMiBackgroundBlendColorCompat(0x4D000000, SRC_OVER)
setPassWindowBlurEnabledCompat(boolean)
setMiBackgroundBlurEnhance(view, enabled, callback)

16.3 标准 RenderEffect 使用位置

文件场景
AnimatedActionBackgroundDrawable.kt通知操作按钮模糊
NotificationStackScrollLayout*.java通知栈模糊
NotificationPanelViewController.java面板模糊
ScrimView.java遮罩模糊
TinyKeyguardPanelViewControllerImpl.kt翻盖锁屏壁纸模糊
KeyguardMaskFadeEffectController.kt时钟 RuntimeShader 效果

16.4 模糊半径值

常用范围:0(关闭)、30、40、100。NotificationShadeDepthController 通过 blurRadiusOfRatio(ratio) 将通知栏展开比例映射到模糊半径。

16.5 典型代码

// MiuiKeyguardBlurInteractor.kt
if (radius > 0) {
    setPassWindowBlurEnabledCompat(true)
    setMiBackgroundBlurModeCompat(SAVE_LAYER)
    setMiBackgroundBlurRadiusCompat(radius)
    setMiViewBlurModeCompat(DRAW_RECT_AND_BLEND)
    clearMiBackgroundBlendColorCompat()
    addMiBackgroundBlendColorCompat(0x4D000000, SRC_OVER)
} else {
    setPassWindowBlurEnabledCompat(false)
    setMiBackgroundBlurModeCompat(CLEAR_BLUR)
}
// NotificationShadeDepthController.kt — 动态计算模糊
combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsExpandedRatio))
combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(transitionToFullShadeProgress))
var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius)
shadeRadius *= (1 - brightnessMirrorSpring.ratio)

十七、Canvas/invalidate 自绘动画

17.1 概述

指标数值
使用文件数73(含 onDraw 实现)

通过 onDraw(Canvas) + invalidate() / postInvalidateOnAnimation() 驱动的逐帧自绘动画。

17.2 代表性自绘动画 View

View场景
LightRevealScrim.kt锁屏唤醒光线揭示动画(Shader)
AuthRippleView.kt生物识别认证涟漪效果
BackPanel.kt预测性返回手势箭头绘制
ReceiverChipRippleView.kt媒体 tap-to-transfer 涟漪
FaceScanningOverlay.kt面部扫描叠加层
ScreenDecorHwcLayer.kt屏幕挖孔/圆角装饰
NotificationBackgroundView.java通知行背景(圆角)
ActivatableNotificationView.java通知触摸激活背景
KeyguardAffordanceView.java锁屏快捷入口圆圈
NavigationHandle.java手势导航药丸

十八、Scroller/OverScroller(滚动动画)

18.1 概述

指标数值
使用文件数78

18.2 自定义滚动行为

实现文件场景
OverScrollerWrapper / OverScrollerInterface通知栈封装标准 OverScroller
SingleShadeLockScreenOverScroller锁屏锁屏通知栏过度滚动
ShadeOverScroller下拉面板面板过度滚动
MIUI 自定义 OverScrollermiui/systemui/notification/widget/内含 FolmeScroller + ViscousFluidInterpolator

18.3 使用此类的 View

NotificationStackScrollLayout, MiuiQSFragment, MiuiPagedTileLayout, KeyguardPanelViewController, FlipRowContainerController, TinyViewPagerDelegate, WalletCardCarousel


十九、Window/Activity 转场动画

19.1 概述

指标数值
相关调用次数42

19.2 使用方式

API次数场景
makeSceneTransitionAnimation5Controls 管理页面(ControlsProviderSelectorActivity 等)
makeCustomAnimation6DetailDialog, AssistManager, EmergencyButton(多数为 0,0 即无动画)
makeSceneTransitionAnimation(共享元素)1LongScreenshotActivity
overridePendingTransition2BrightnessDialog(fade_in/out), AppClipsActivity(0,0)

二十、Interpolator(缓动曲线)汇总

20.1 总览

SystemUI 中使用了 30+ 种 Interpolator,来自 4 大来源。

20.2 AOSP 标准 Interpolator

Interpolator典型场景
LinearInterpolator匀速变化
AccelerateDecelerateInterpolator标准加减速
AccelerateInterpolator退出动画
DecelerateInterpolator进入动画
OvershootInterpolator超越目标值后回弹
AnticipateOvershootInterpolator先后退再超越
PathInterpolator(23 文件)自定义贝塞尔曲线

20.3 AOSP SystemUI Interpolators 工具类

常量场景
Interpolators.LINEAR线性(87次)
Interpolators.FAST_OUT_SLOW_INMaterial 标准(47次)
Interpolators.ALPHA_IN / ALPHA_OUT淡入/淡出
Interpolators.EMPHASIZEDMaterial 3 强调
Interpolators.EMPHASIZED_DECELERATEM3 强调减速
Interpolators.STANDARD / STANDARD_DECELERATE标准/标准减速
Interpolators.TOUCH_RESPONSE触摸响应
Interpolators.DECELERATE_QUINT五次减速

20.4 MIUI 自定义 Interpolator

PhysicBasedInterpolator

基于阻尼谐振子数学模型:e^(r*t) * (c1*cos(w*t) + c2*sin(w*t)) + 1.0

// RowAnimationUtils.kt — 通知触摸缩放
// 按下: damping=0.9, response=0.8, duration=450ms (缩放到 0.95)
// 抬起: damping=0.6, response=0.556, duration=450ms (回到 1.0)

使用位置:RowAnimationUtils.kt, FlipRowAnimationUtils.kt, KeyguardMoveHelper.java, EdgePanelParams.kt, QSAnimation.kt, ModalControllerImpl.kt, MiuiNotificationAnimationExtensions.kt

SpringInterpolator

同样基于阻尼谐振子,但继承 BaseInterpolator 支持 XML 属性。

// MiuiAnimationUtils.kt
generalWakeupTranslateAnimation: damping=0.95, response=0.8571, duration=700ms
generalWakeupAlphaAnimation: damping=0.9, response=0.86, duration=350ms
generalWakeupScaleAnimation: damping=0.9, response=0.86, duration=350ms

MiuiInterpolators 工具类

MIUI_ALPHA_IN  = new SineEaseOutInterpolator();
MIUI_ALPHA_OUT = new SineEaseOutInterpolator();
CUBIC_EASE_OUT = new CubicEaseOutInterpolator();
CUBIC_EASE_IN_OUT = new CubicEaseInOutInterpolator();
EXP_EASE_OUT   = new ExponentialEaseOutInterpolator();

ViscousFluidInterpolator

miuix.overscroller 移植,用于通知栈 fling 减速,VISCOUS_FLUID_SCALE = 8.0f

20.5 Miuix SDK Interpolator

Interpolator包路径
CubicEaseInInterpolatormiuix.view.animation
CubicEaseOutInterpolatormiuix.view.animation
CubicEaseInOutInterpolatormiuix.view.animation
ExponentialEaseOutInterpolatormiuix.view.animation
SineEaseOutInterpolatormiuix.view.animation

20.6 Compose Easing

Easing使用场景
CubicBezierEasing(...)自定义贝塞尔曲线
Easings.StandardAccelerate标准加速
Easings.StandardDecelerate标准减速
Easings.PredictiveBack预测性返回
Easings.Linear线性
FastOutSlowInEasingMaterial 标准

20.7 其他自定义 Interpolator

Interpolator文件用途
BounceInterpolatorstatusbar/phone/BounceInterpolator.java弹跳效果
SystemUIInterpolatorsvolume/SystemUIInterpolators.java音量面板
QSExpansionPathInterpolatorQS快设展开曲线
FontInterpolator / TextInterpolatoranimation文字形变
TruncatedInterpolatorlowlight截断插值

二十一、架构总结与演进趋势

21.1 三套动画体系并存

┌─────────────────────────────────────────────────────────┐
│                    SystemUI 动画架构                      │
├──────────────────┬──────────────────┬───────────────────┤
│   AOSP 原生层     │    MIUI 定制层    │   Compose 新 UI 层 │
├──────────────────┼──────────────────┼───────────────────┤
│ ValueAnimator    │ Folme            │ animateXAsState    │
│ ObjectAnimator   │ FolmeEase        │ AnimatedVisibility │
│ AnimatorSet      │ AnimState        │ Animatable         │
│ SpringAnimation  │ AnimConfig       │ SceneTransition    │
│ FlingAnimation   │ MiBlurCompat     │ AnimatedContent    │
│ PhysicsAnimator  │ PhysicBasedInterp│ Crossfade          │
│ Transition       │ MiuiInterpolators│ updateTransition   │
│ MotionLayout     │                  │                    │
├──────────────────┼──────────────────┼───────────────────┤
│ src/             │ miui*/           │ compose/           │
│ 通用基础动画      │ MIUI 差异化交互   │ 新场景过渡+声明式UI │
└──────────────────┴──────────────────┴───────────────────┘

21.2 关键洞察

  1. Folme 是 MIUI 层的绝对核心(151 文件),但在 AOSP 层零使用,形成了清晰的分层边界。

  2. ValueAnimator.ofFloat(0f, 1f) 作为万能进度驱动器是整个代码库中最普遍的惯用法,一个 Animator 驱动多个派生属性值。

  3. 弹簧物理是 MIUI 的动画哲学:Folme 的 SPRING_PHY 占比 >85%,几乎所有 MIUI 交互都使用弹簧缓动。

  4. Compose 层偏好 tween 而非 spring(187 vs 69),与 MIUI 层的弹簧偏好形成对比。

  5. 自研 SceneTransitionLayout 是最大的动画投资(40 个过渡定义文件),是锁屏↔通知栏↔快设等核心场景的过渡基础。

  6. 模糊动画是 SystemUI 的视觉基石(180+ 文件),MiBlurCompat 占主导(2.6:1)。

  7. AVD 是最多的动画资源文件(257 个 XML),主要用于 QS 磁贴和锁屏图标的状态切换。

21.3 演进趋势

方向证据
新 UI → Compose Animation177 文件已迁移,Scene Framework 是新架构核心
MIUI 交互 → Folme几乎所有 MIUI 新代码使用 Folme 状态机模式
传统 View Animation 减少XML anim 文件集中在旧模块,新代码少用
MotionLayout 稳定但不扩展仅用于 PIN/Pattern/QS Header/Volume,未见新增
Lottie 定位于复杂状态动画集中在生物识别和教程,不会替代代码动画

本文档基于 dev-2604-26q2 分支代码静态分析生成,统计数据为近似值。