Android动画分类及原理
Android动画主要分为两大类:窗口动画和窗口内部的app动画。这两类动画在视觉效果、控制方式和应用场景上有所不同。
一、窗口动画
定义:窗口动画主要涉及Activity或窗口(Window)的进入、退出等视觉效果。
特点:
- 通常由系统控制,但开发者可以通过预定义的动画资源或自定义动画资源来设置。
- 典型的设置方式是通过
overridePendingTransition()
方法。
技术实现:
- 与
AppWindowAnimator
、WindowStateAnimator
等系统类相关,这些类负责控制窗口状态的变化及动画效果。 - 当Activity的生命周期事件(如启动、退出)发生时,系统会根据设置的动画资源执行相应的动画效果,以实现视觉上的平滑过渡。
二、窗口内部的app动画
定义:窗口内部的app动画更加多样化和灵活,包括帧动画、补间动画(视图动画)、属性动画和转场动画。
1. 帧动画(Frame Animation)
- 特点:通过连续播放一系列图像帧来创建动画效果。
- 原理:使用
AnimationDrawable
类加载XML定义的帧图片,通过定时更新当前显示的帧来实现动画。 - 使用场景:适合简单的动画效果,如GIF动画。
2. 补间动画(Tween Animation)/ 视图动画(View Animation)
- 子类型:平移(Translate)、旋转(Rotate)、缩放(Scale)、透明度(Alpha)。
- 特点:通过指定动画开始和结束的属性值,系统自动计算变化过程。
- 原理:基于View的动画,通过修改Canvas的绘制矩阵来实现动画效果,但不改变View的实际属性。
- 使用场景:适合简单的视图动画效果,如页面切换时的淡入淡出。
- 底层解析:
- AnimationUtils.loadAnimation()开始加载解析,通过xmlParse解析相应字段节点根据不同动画类型创建动画;
- View.startAnimation(xxx)触发invalidate()重绘,draw()根据动画标志位计算得到animation,并更新transformation,触发下一次绘制;
- 结果返回给View在绘制时对画布Canvas做矩阵变换从而实现动画。
- 这是在draw层面实现,只有视觉变化,实际属性不变。
3. 属性动画(Property Animation)
- 特点:通过动态修改对象的属性值来实现动画效果,功能强大且灵活。
- 原理:执行
animator.start()
后,动画作为回调注册到AnimationHandler
,并通过Choreographer
实现精确时间控制和插值计算。 - 使用场景:适用于需要改变对象实际属性的复杂动画效果,如非线性动画。
- 实现非线性动画: 通过ValueAnimator或者ObjectAnimator结合Interpolator(插值器)来实现非线性动画。
- 其中,插值器(Interpolator)定义了动画值随时间变化的速率。
Android提供了多种内置的插值器,如AccelerateInterpolator(加速插值器)、DecelerateInterpolator(减速插值器)、AccelerateDecelerateInterpolator(先加速后减速插值器)等。此外,你还可以自定义插值器来满足特定的需求。
以下是一个使用ObjectAnimator和AccelerateDecelerateInterpolator实现非线性动画的示例:
// 假设你有一个名为view的视图,你想要对其透明度进行动画处理
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f);
animator.setDuration(3000);
animator.setInterpolator(new AccelerateDecelerateInterpolator()); // 使用先加速后减速的插值器
animator.start();
4. 转场动画(Transition Animation)
- 特点:用于界面切换时的过渡效果,可包含多种动画效果的组合。
- 原理:通过
Window.setEnterTransition()
、Window.setExitTransition()
等方法设置,或使用makeSceneTransitionAnimation
实现共享元素的过渡效果。 - 使用场景:适合界面切换时提供平滑过渡效果的场景,特别是当界面间存在共享元素时。
三、共享动画
定义:共享动画是一种特殊的转场动画,允许在两个界面之间共享相同元素,并通过动画效果展示这些元素从一个界面到另一个界面的转移过程。
特点:元素共享,流畅过渡。
原理:
- 元素标识:通过
transitionName
属性为共享元素设置唯一标识符。 - 动画触发:调用
makeSceneTransitionAnimation
方法,并传入当前界面的视图和对应的新界面的视图,来触发共享动画。
使用方法:
系统根据transitionName
找到对应的共享元素,计算其在新界面中的位置和大小,然后创建并执行动画。
- 设置transitionName:在源界面和目标界面的XML布局文件中,为需要共享的元素设置相同的
transitionName
属性。 - 启动新界面:在源界面中,当用户点击某个元素并触发界面跳转时,通过调用
makeSceneTransitionAnimation
方法并传入相应的视图,来启动带有共享动画的新界面。 - 处理目标界面:在目标界面中,确保布局的根元素或相应的容器支持共享动画的过渡效果。
四、动画原理及流程梳理
动画的整个过程从初始化设置开始,通过Choreographer
与硬件Vsync信号同步,逐步计算并更新动画属性,最终将动画效果绘制到屏幕上。对于窗口动画,虽然细节有所不同,但整体流程也遵循类似的模式。
1. 初始化动画
- 动画定义:通过代码或XML资源定义动画的各种属性,如类型(
ObjectAnimator
、ValueAnimator
等)、持续时间、插值器、起始值与结束值等。 - 创建
ValueAnimator
实例:对于使用ValueAnimator
的动画,创建其实例并设置必要的动画参数。
2. 注册动画到Choreographer
- 动画注册:调用
ValueAnimator
的start()
方法时,动画被注册到Choreographer
。Choreographer
是Android提供的一个用于协调动画、输入事件等时间相关任务的类。 - Vsync信号监听:
Choreographer
监听由硬件产生的Vsync信号,这些信号用于同步屏幕刷新。每当接收到Vsync信号时,Choreographer
会调度一次动画帧的更新。
3. 动画帧的更新
- 计算属性值:在每次Vsync周期中,
Choreographer
调用ValueAnimator
的更新逻辑,根据插值器等参数计算当前动画的属性值。 - 回调监听:
ValueAnimator
通过AnimatorUpdateListener
的回调方法通知开发者当前动画的属性值。开发者可以在此回调中更新UI组件的状态。
4. UI绘制
- UI组件更新:在回调方法中,根据动画的属性值更新UI组件(如视图的位置、大小、颜色等)。
- 视图系统绘制:Android视图系统根据UI组件的状态变化安排重绘操作。
- SurfaceFlinger合成:绘制操作的结果被传递给
SurfaceFlinger
,SurfaceFlinger
负责将多个应用的UI合成为最终的屏幕显示。
5. 窗口动画(额外说明)
- 窗口状态变化:当Activity的生命周期事件(如
onResume()
、onPause()
)发生时,系统会检测到窗口状态的变化。 - 动画执行:根据在
style.xml
中设置的窗口动画资源(如android:windowEnterAnimation
、android:windowExitAnimation
等),系统通过AppWindowAnimator
或WindowStateAnimator
等类控制动画的执行。 - 动画绘制:窗口动画的每一帧也通过视图系统绘制到屏幕上,并最终由
SurfaceFlinger
合成显示。这一流程与App动画的绘制过程相似,但动画的触发和控制方式有所不同。