android 动画详解

发布时间:2026/10/6 17:59:23

android 动画详解 Android 动画详解从原理到实战Android 动画体系经历了从传统 View 动画 → 属性动画 → 过渡动画 → MotionLayout → Jetpack Compose 的演进。以下从分类、原理、API、实战四个维度系统梳理。一、动画分类总览Android 动画按实现方式可分为四大类类别包名适用场景特点View 动画补间动画android.view.animation简单 UI 动效只改变绘制位置不改变实际属性帧动画Drawable 动画android.graphics.drawable加载动画、序列帧逐帧切换图片内存占用高属性动画android.animation任意对象属性动画真正改变对象属性功能最强大过渡动画android.transitionActivity/Fragment 切换场景切换间的连贯体验MotionLayoutandroidx.constraintlayout.motion复杂交互动效基于 ConstraintLayout 的声明式动画Compose 动画androidx.compose.animation现代 UI 开发声明式、状态驱动、代码简洁二、View 动画补间动画⚠️已不推荐View 动画只能作用于 View且只改变绘制位置不改变实际属性如按钮移动后点击区域仍在原处。新项目请优先使用属性动画。2.1 四种基本变换动画类型类名属性平移TranslateAnimationfromXDelta,toXDelta,fromYDelta,toYDelta缩放ScaleAnimationfromXScale,toXScale,fromYScale,toYScale旋转RotateAnimationfromDegrees,toDegrees,pivotX,pivotY透明度AlphaAnimationfromAlpha,toAlpha2.2 XML 定义xml!-- res/anim/scale_rotate.xml -- set xmlns:androidhttp://schemas.android.com/apk/res/android android:duration1000 android:fillAftertrue android:interpolatorandroid:anim/accelerate_decelerate_interpolator scale android:fromXScale1.0 android:toXScale2.0 android:fromYScale1.0 android:toYScale2.0 android:pivotX50% android:pivotY50% / rotate android:fromDegrees0 android:toDegrees360 android:pivotX50% android:pivotY50% / /set2.3 代码调用kotlinval animation AnimationUtils.loadAnimation(context, R.anim.scale_rotate) view.startAnimation(animation)三、帧动画Drawable 动画将一系列 Drawable 按时间间隔逐帧显示适合简单的加载动画。xml!-- res/drawable/loading_animation.xml -- animation-list xmlns:androidhttp://schemas.android.com/apk/res/android android:oneshotfalse item android:drawabledrawable/frame1 android:duration100 / item android:drawabledrawable/frame2 android:duration100 / item android:drawabledrawable/frame3 android:duration100 / /animation-listkotlinval imageView: ImageView findViewById(R.id.imageView) imageView.setImageResource(R.drawable.loading_animation) val animationDrawable imageView.drawable as AnimationDrawable animationDrawable.start()⚠️注意帧动画会预加载所有帧到内存图片过多或过大时容易造成 OOM。建议用 Lottie 替代复杂帧动画。四、属性动画Property Animation属性动画是 Android 3.0API 11引入的动画框架真正修改对象的属性值功能强大且灵活。4.1 核心类表格类作用ValueAnimator动画引擎计算动画值不直接操作对象ObjectAnimatorValueAnimator子类直接操作目标对象的属性AnimatorSet组合多个动画控制执行顺序Interpolator插值器定义动画变化速率TypeEvaluator估值器定义属性值的计算方式4.2 ValueAnimatorkotlinval animator ValueAnimator.ofFloat(0f, 100f).apply { duration 1000 interpolator AccelerateDecelerateInterpolator() addUpdateListener { animation - val value animation.animatedValue as Float // 手动将计算值应用到目标对象 view.translationX value } } animator.start()4.3 ObjectAnimator最常用kotlin// 平移 ObjectAnimator.ofFloat(view, translationX, 0f, 200f).apply { duration 1000 start() } // 旋转 ObjectAnimator.ofFloat(view, rotation, 0f, 360f).apply { duration 1000 start() } // 透明度 ObjectAnimator.ofFloat(view, alpha, 1f, 0f, 1f).apply { duration 1500 start() } // 背景色变化需要 ArgbEvaluator ObjectAnimator.ofInt(view, backgroundColor, Color.RED, Color.BLUE).apply { duration 2000 setEvaluator(ArgbEvaluator()) start() }4.4 可动画的 View 属性属性说明translationX/translationY相对于 left/top 的偏移x/y最终位置left translationXrotation/rotationX/rotationY2D/3D 旋转scaleX/scaleY缩放pivotX/pivotY旋转/缩放的中心点alpha透明度width/height宽高需配合 wrapper4.5 AnimatorSet 组合动画kotlinval fadeOut ObjectAnimator.ofFloat(view, alpha, 1f, 0f) val mover ObjectAnimator.ofFloat(view, translationX, -500f, 0f) val fadeIn ObjectAnimator.ofFloat(view, alpha, 0f, 1f) AnimatorSet().apply { play(mover).with(fadeIn).after(fadeOut) // fadeOut 先执行然后 mover 和 fadeIn 同时执行 duration 2000 start() }4.6 ViewPropertyAnimator链式调用kotlinview.animate() .translationX(200f) .translationY(100f) .rotation(360f) .alpha(0.5f) .setDuration(1000) .setInterpolator(BounceInterpolator()) .withLayer() // 开启硬件层加速 .withStartAction { /* 动画开始前 */ } .withEndAction { /* 动画结束后 */ } .start()ViewPropertyAnimator内部优化了多个属性同时动画的性能比多个ObjectAnimator更高效。4.7 插值器Interpolator插值器效果LinearInterpolator匀速AccelerateInterpolator加速DecelerateInterpolator减速AccelerateDecelerateInterpolator先加速后减速BounceInterpolator弹跳效果OvershootInterpolator冲过头再回弹AnticipateInterpolator先回退再前进AnticipateOvershootInterpolator先回退冲过头再回弹4.8 XML 声明属性动画xml!-- res/animator/property_animator.xml -- set android:orderingsequentially objectAnimator android:propertyNamex android:duration500 android:valueTo400 android:valueTypeintType / objectAnimator android:propertyNamealpha android:duration500 android:valueTo1f / /setkotlinval set AnimatorInflater.loadAnimator(context, R.animator.property_animator) as AnimatorSet set.setTarget(view) set.start()五、过渡动画Transition5.1 Activity 过渡动画kotlin// 传统方式API 21 以下兼容 val intent Intent(this, TargetActivity::class.java) startActivity(intent) overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left)5.2 共享元素过渡Shared Elementkotlin// Activity A val options ActivityOptions.makeSceneTransitionAnimation( this, sharedImageView, shared_image // transitionName 必须匹配 ) startActivity(intent, options.toBundle()) // Activity B 的 layout 中 ImageView android:idid/sharedImageView android:transitionNameshared_image ... /5.3 Fragment 过渡kotlinval fragmentB FragmentB() fragmentB.sharedElementEnterTransition TransitionInflater.from(context) .inflateTransition(android.R.transition.move) supportFragmentManager.beginTransaction() .replace(R.id.container, fragmentB) .addSharedElement(sharedView, shared_name) .commit()六、MotionLayoutMotionLayout 是 ConstraintLayout 的子类通过声明式 XML 定义复杂动画是传统 View 系统中处理复杂交互动画的最佳选择。6.1 核心概念概念说明MotionScene动画场景描述文件ConstraintSet定义布局的起始/结束状态Transition定义两个状态之间的过渡KeyFrameSet关键帧控制中间状态OnClick/OnSwipe触发方式6.2 基本示例xml!-- res/layout/activity_main.xml -- androidx.constraintlayout.motion.widget.MotionLayout xmlns:androidhttp://schemas.android.com/apk/res/android xmlns:apphttp://schemas.android.com/apk/res-auto android:layout_widthmatch_parent android:layout_heightmatch_parent app:layoutDescriptionxml/scene View android:idid/box android:layout_width64dp android:layout_height64dp android:backgroundcolor/purple / /androidx.constraintlayout.motion.widget.MotionLayoutxml!-- res/xml/scene.xml -- MotionScene xmlns:apphttp://schemas.android.com/apk/res-auto !-- 起始状态 -- ConstraintSet android:idid/start Constraint android:idid/box android:layout_width64dp android:layout_height64dp app:layout_constraintStart_toStartOfparent app:layout_constraintTop_toTopOfparent / /ConstraintSet !-- 结束状态 -- ConstraintSet android:idid/end Constraint android:idid/box android:layout_width64dp android:layout_height64dp app:layout_constraintEnd_toEndOfparent app:layout_constraintBottom_toBottomOfparent / /ConstraintSet !-- 过渡定义 -- Transition app:constraintSetStartid/start app:constraintSetEndid/end app:duration1000 OnClick app:targetIdid/box app:clickActiontoggle / /Transition /MotionScene6.3 关键帧KeyFramexmlTransition ... KeyFrameSet !-- 中间位置关键帧动画 50% 时位于屏幕中心 -- KeyPosition app:framePosition50 app:motionTargetid/box app:keyPositionTypeparentRelative app:percentX0.5 app:percentY0.5 / !-- 中间属性关键帧50% 时旋转 180 度 -- KeyAttribute app:framePosition50 app:motionTargetid/box android:rotation180 / /KeyFrameSet /Transition6.4 代码控制kotlinmotionLayout.transitionToState(R.id.end) // 过渡到结束状态 motionLayout.transitionToStart() // 回到起始状态 motionLayout.progress 0.5f // 设置进度0~1 motionLayout.setTransition(R.id.start, R.id.end) // 设置过渡七、Jetpack Compose 动画推荐2026 年Jetpack Compose 已成为 Android UI 开发的默认方式其动画 API 声明式、简洁且功能强大。7.1 状态驱动动画kotlinComposable fun AnimatedBox() { var expanded by remember { mutableStateOf(false) } // 尺寸动画 val size by animateDpAsState( targetValue if (expanded) 120.dp else 60.dp, animationSpec tween(durationMillis 500, easing FastOutSlowInEasing), label size ) // 颜色动画 val color by animateColorAsState( targetValue if (expanded) Color.Green else Color.Blue, label color ) Box( modifier Modifier .size(size) .background(color, CircleShape) .clickable { expanded !expanded } ) }7.2 可见性动画kotlinvar visible by remember { mutableStateOf(true) } AnimatedVisibility( visible visible, enter fadeIn() slideInHorizontally(), exit fadeOut() slideOutHorizontally() ) { Text(Hello Compose!) }7.3 内容切换动画kotlinvar selected by remember { mutableStateOf(false) } Crossfade(targetState selected, label crossfade) { state - when (state) { true - Icon(Icons.Default.Check, null) false - Icon(Icons.Default.Close, null) } }7.4 内容变更动画kotlinvar count by remember { mutableIntStateOf(0) } AnimatedContent( targetState count, transitionSpec { if (targetState initialState) { slideInVertically { it } fadeIn() togetherWith slideOutVertically { -it } fadeOut() } else { slideInVertically { -it } fadeIn() togetherWith slideOutVertically { it } fadeOut() } }, label count ) { targetCount - Text(text $targetCount, fontSize 48.sp) }7.5 无限循环动画kotlinval infiniteTransition rememberInfiniteTransition(label pulse) val scale by infiniteTransition.animateFloat( initialValue 1f, targetValue 1.5f, animationSpec infiniteRepeatable( animation tween(1000), repeatMode RepeatMode.Reverse ), label scale ) Box( modifier Modifier .size(100.dp) .scale(scale) .background(Color.Red, CircleShape) )7.6 手势驱动动画kotlinval offset remember { Animatable(Offset.Zero, Offset.VectorConverter) } Box( modifier Modifier .offset { offset.value.toIntOffset() } .size(100.dp) .background(Color.Blue) .pointerInput(Unit) { detectDragGestures( onDrag { change, dragAmount - change.consume() scope.launch { offset.snapTo(offset.value dragAmount) } }, onDragEnd { scope.launch { // 弹簧回弹到原点 offset.animateTo( targetValue Offset.Zero, animationSpec spring( dampingRatio Spring.DampingRatioMediumBouncy, stiffness Spring.StiffnessLow ) ) } } ) } )7.7 共享元素过渡ComposekotlinSharedTransitionLayout { AnimatedContent( targetState selectedItem, transitionSpec { (fadeIn() togetherWith fadeOut()).using(SizeTransform(clip false)) } ) { item - if (item null) { // 列表页 LazyColumn { items(items) { photo - Image( painter rememberAsyncImagePainter(photo.url), contentDescription null, modifier Modifier .sharedElement( state rememberSharedContentState(key photo.id), animatedVisibilityScope thisAnimatedContent ) .clickable { selectedItem photo } ) } } } else { // 详情页 Image( painter rememberAsyncImagePainter(item.url), contentDescription null, modifier Modifier .sharedElement( state rememberSharedContentState(key item.id), animatedVisibilityScope thisAnimatedContent ) .fillMaxSize() ) } } }八、动画核心机制8.1 Vsync Choreographer 机制Android 动画的流畅性依赖于Vsync垂直同步和Choreographer的协同工作Vsync 信号显示器硬件每帧刷新完成后发出同步信号60Hz 16.6ms/帧120Hz 8.3ms/帧Choreographer通过postCallback()注册动画回调在 Vsync 信号到达时触发doFrame()动画更新ValueAnimator计算当前帧的属性值 → 调用Interpolator计算插值 → 调用TypeEvaluator计算最终值 → 更新 View 属性 →invalidate()触发重绘SurfaceFlinger合成所有图层输出到屏幕8.2 属性动画计算流程plainstart() → Choreographer 注册回调 → 等待 Vsync 信号 → doFrame(frameTimeNanos) → 计算 elapsedFraction (0~1) → Interpolator 计算 interpolatedFraction → TypeEvaluator 计算属性值 → 更新目标对象属性 → invalidate() 请求重绘 → 下一帧循环直到动画结束九、性能优化最佳实践9.1 避免掉帧表格优化手段说明使用硬件层view.animate().withLayer()或view.setLayerType(View.LAYER_TYPE_HARDWARE, null)避免主线程阻塞动画回调中不做 IO/复杂计算减少过度绘制使用 GPU 调试模式分析控制同时动画数MotionLayout 同时动画 50 个 View 可能掉帧使用 Profile GPU Rendering开发者选项中开启查看各阶段耗时9.2 各场景选型建议场景推荐方案简单属性变化位移、透明度ObjectAnimator/ViewPropertyAnimator复杂交互动效折叠头、拖拽MotionLayout新项目的所有动画Jetpack Compose Animation API列表项增删动画RecyclerView.ItemAnimator/ ComposeLazyColumnAnimatedVisibility跨页面共享元素SharedElementTransition/ ComposeSharedTransitionLayout复杂帧动画Lottie替代 AnimationDrawable9.3 Compose 动画性能Compose 动画基于重组Recomposition和智能跳过只有状态变化的 Composable 会重新执行使用remember缓存动画状态避免不必要的计算复杂动画使用LaunchedEffectAnimatable精确控制十、总结对比维度View 动画属性动画MotionLayoutCompose 动画实际改变属性❌ 否✅ 是✅ 是✅ 是非 View 对象❌ 不支持✅ 支持❌ 仅 View✅ 任意状态代码量中中少XML 声明少复杂交互❌ 困难⚠️ 较复杂✅ 擅长✅ 擅长维护性一般一般好优秀推荐度⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐2026 年建议新项目直接使用Jetpack Compose Compose Animation API维护中的传统项目复杂动画迁移到MotionLayout简单动画使用属性动画替代 View 动画。
延伸阅读

更多相关文章

2026/10/2 8:56:47

StringBuffer、StringBuilder、StringJoiner区别

一、StringBuffer线程安全性:✅ 线程安全(所有方法都是 synchronized)。可变性:可变字符序列。性能:由于同步开销,性能比 StringBuilder 差。适用场景:多线程环境下需要频繁修改字符串时使用。J…

2026/10/5 15:29:09

如何将C++工程变为Qt工程

在 <PropertyGroup label"Global"> 中添加<PropertyGroup label"Global"> <KeyWord>Qt4vsv1.0</KeyWord>重启VS后会有Qt属性&#xff0c;也可以更改Qt的版本 随着本地环境的变化&#xff0c;这个keyword值的版本可以需要升级

2026/10/5 5:41:24

老旧电脑硬件升级完全指南:从诊断到实操的性能重生之路

每台老旧电脑都隐藏着性能潜力。根据2024年Statista数据&#xff0c;全球约有3.2亿台使用超过5年的个人电脑仍在服役&#xff0c;其中65%的性能瓶颈源于可升级硬件而非核心架构老化。本指南将系统拆解电脑升级的完整流程&#xff0c;通过10实战案例、20兼容性图表和15优化脚本&…

2026/10/6 17:54:32

扣子COZE多轮对话客服搭建指南:意图识别、知识库与上线避坑

简介&#xff1a;面向有一定编程基础、希望在低代码环境中落地智能客服的开发者或企业技术人员&#xff0c;这份资料系统介绍了基于扣子COZE平台构建多轮对话智能客服助手的完整方案&#xff0c;重点解决官网场景下用户问题自动应答、意图识别、上下文跟踪、服务推荐及API集成等…

2026/10/6 17:54:32

华为eNSP从零开始:依赖安装、VLAN配置与三层互通实战

简介&#xff1a;华为ENSP是华为官方的网络模拟平台&#xff0c;这份配置文档围绕其常用网络技术整理&#xff0c;尤其适合网络初学者、备考华为认证或需要进行协议实验复现的工程师。内容以设备配置流程为主线&#xff0c;系统覆盖VLAN划分与trunk放行、VLAN间路由&#xff08…

2026/10/6 17:54:32

Agent开发范式转移:从工程化思维到稳定落地的实战指南

很多人问过我&#xff0c;Agent 开发到底跟传统后端开发有什么本质区别。看完 Alibaba Cloud AI Agent Handbook 和相关的开发者调研数据&#xff0c;我的感受是&#xff1a;Agent 不是又一种框架&#xff0c;而是把“软件从被动执行指令&#xff0c;变成主动理解目标”的一次范…

2026/10/6 17:54:32

PyTorch自定义C++/CUDA算子实战:从原理到性能优化

1. 为什么需要自定义算子 1.1 PyTorch 算子的两种来源 我一直觉得&#xff0c;很多人对“自定义算子”这个词的第一反应是“这是那些做框架的人才会碰的东西”。实际上 PyTorch 每天在用的所有功能&#xff0c;无论是 torch.add 还是 conv2d &#xff0c;本质上都能归成两…

2026/10/6 17:49:32

汇川IS620N伺服回零模式调试全解析:从模式1到35的踩坑经验

最开始接触汇川IS620N回零模式的时候&#xff0c;我印象最深的是手册里那一张密密麻麻的模式定义表&#xff1a;从模式1到模式35&#xff0c;光看编号和方向组合就够让人头疼。当时我心想&#xff0c;不就找个原点嘛&#xff0c;搞这么复杂干什么。结果第一次上电调试&#xff…

2026/10/5 6:32:56

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起&#xff1a;为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高&#xff0c;很多人第一次听到会以为是某个新模型的名字&#xff0c;其实它更像是一种思路——把Jev模型的能力当作底座&#xff0c;通过Agent的方式去接管浏览器&#xf…

2026/10/6 4:01:51

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同"&#xff1a;多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西&#xff0c;大概率会有一种感觉&#xff1a;单个 Agent 能做的事情&#xff0c;其实很快就摸到天花板了。你给它一个提示词&#xff0c;挂几个工…

2026/10/6 17:46:51

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 0:03:23

MR25H40CDF+STM32F031C6工业级高可靠数据存储方案

1. 项目概述&#xff1a;为什么在工业现场非得用 MR25H40CDF 配 STM32F031C6 做数据存储&#xff1f;在工厂产线的 PLC 控制柜里、在风电变流器的散热片背面、在矿井监测终端的金属外壳下&#xff0c;你经常能看到一块指甲盖大小的黑色芯片——它既不是 Flash&#xff0c;也不是…

2026/10/6 0:03:23

MRAM+STM32工业断电数据保全实战指南

1. 项目概述&#xff1a;为什么在工业现场非得用 MR25H40CDF 配 STM32F031C6 做数据存储&#xff1f;在工厂产线的PLC柜里、在野外无人值守的环境监测终端里、在高速运转的包装机控制板上&#xff0c;你经常能看到一块指甲盖大小的黑色芯片&#xff0c;旁边贴着“MR25H40CDF”丝…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑