1 Window、WindowManager、WMS
Window:在Android视图体系中Window就是一个窗口的概念。Android中所有的视图都是依赖于Window显示的。
WindowManager:对Window的管理,包括新增、更新和删除等。
WMS:窗口的最终管理者,它负责窗口的启动、添加和删除,另外窗口的大小和层级也是由WMS进行管理。
2 Window的基本概念
2.1 常见Window
2.2 窗口的次序
2.3 Window分类
Application Window:Activity就是一个典型的应用程序窗口。
Sub Window:子窗口,顾名思义,它不能独立存在,需要附着在其他窗口才可以,PopupWindow就属于子窗口。
System Window:输入法窗口、系统音量条窗口、系统错误窗口都属于系统窗口
2.3.1 ApplicationWindow
public static final int FIRST_APPLICATION_WINDOW = 1;
public static final int TYPE_BASE_APPLICATION = 1;
public static final int TYPE_APPLICATION = 2;
public static final int TYPE_APPLICATION_STARTING = 3;
public static final int TYPE_DRAWN_APPLICATION = 4;
public static final int LAST_APPLICATION_WINDOW = 99;
2.3.2 Sub Window
public static final int FIRST_SUB_WINDOW = 1000;
public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;
public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;
public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3;
public static final int TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW +4;
public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW+5;
public static final int LAST_SUB_WINDOW = 1999;
2.3.3 System Window
public static final int FIRST_SYSTEM_WINDOW = 2000;
public static final int TYPE_STATUS_BAR =FIRST_SYSTEM_WINDOW;
public static final int TYPE_SEARCH_BAR =FIRST_SYSTEM_WINDOW+1;
public static final int TYPE_PHONE =FIRST_SYSTEM_WINDOW+2;
public static final int TYPE_SYSTEM_ALERT =FIRST_SYSTEM_WINDOW+3;
public static final int TYPE_KEYGUARD =FIRST_SYSTEM_WINDOW+4;
public static final int TYPE_TOAST =FIRST_SYSTEM_WINDOW+5;
...
2.4 窗口的次序
在 Android WindowManagerService 的窗口管理体系中,WindowState 的主序(主层级)和子序(子层级)主要是用于描述窗口在屏幕显示中的层级关系和顺序,确保窗口按照优先级正确显示。
1. 主序(主层级)
主序决定窗口的大层级(Z-Order),是由窗口的 类型(WindowManager.LayoutParams.type
)决定的,通常分为以下几类:
常见主层级
-
系统优先窗口:
-
包括状态栏(Status Bar)、导航栏(Navigation Bar)、系统对话框等。
-
通常优先级最高,显示在所有应用窗口之上。
-
示例:
TYPE_STATUS_BAR
(状态栏)TYPE_NAVIGATION_BAR
(导航栏)TYPE_SYSTEM_ERROR
(系统错误提示)
-
-
应用窗口:
-
包括普通的 Activity 窗口。
-
属于应用正常使用的显示内容,通常显示在用户界面中间层。
-
示例:
TYPE_APPLICATION
(普通应用窗口)TYPE_APPLICATION_OVERLAY
(悬浮窗口,如悬浮按钮)
-
-
子窗口(附属窗口) :
-
附属于主窗口的对话框或弹窗。
-
示例:
TYPE_APPLICATION_PANEL
(应用面板,如弹出的对话框)TYPE_APPLICATION_SUB_PANEL
(子面板,如上下文菜单)
-
-
其他特殊窗口:
-
包括 Toast 提示、悬浮窗口等。
-
示例:
TYPE_TOAST
(Toast 提示)TYPE_PHONE
(电话窗口)
-
2. 子序(子层级)
子序是在主序之内进一步排序的依据,主要由窗口的 Z-Order 和显示优先级决定。子序主要解决相同类型的窗口内部如何排序的问题。
常见影响因素
-
窗口层级值(
mLayer
) :- WindowManagerService 为每个窗口计算其层级值
mLayer
。 - 通常根据窗口类型和 Z-Order 的规则动态计算。
- WindowManagerService 为每个窗口计算其层级值
-
窗口 Token 顺序:
- 多个窗口共用一个
WindowToken
(例如同一任务栈的多个 Activity 窗口)时,子序按照创建顺序或焦点状态调整。
- 多个窗口共用一个
-
Activity/Task 窗口关系:
- 例如,多个 Activity 窗口之间,当前 Activity 的窗口通常优先显示。
-
动画效果影响:
- 某些窗口动画(如打开、关闭过渡动画)可能临时改变子序。
3. 主序和子序的计算流程
主序和子序的计算逻辑主要在 WindowManagerService 的 WindowState
类中完成:
-
主序计算:
-
按窗口类型,确定主层级:
java 复制代码 int baseLayer = getBaseLayer(params.type);
-
-
子序调整:
-
根据 Token 顺序或窗口特性调整子序:
java 复制代码 int layer = baseLayer + token.layerOffset;
-
-
最终层级确定:
-
如果有动画或临时调整,动态更新子序:
java 复制代码 layer += animationLayerAdjustment;
-
4. 示例:主序与子序的关系
以普通应用窗口和悬浮窗口为例:
-
主序:
- 应用窗口的主序(
TYPE_APPLICATION
)低于系统窗口。 - 悬浮窗口(
TYPE_APPLICATION_OVERLAY
)的主序比普通应用窗口高。
- 应用窗口的主序(
-
子序:
- 在
TYPE_APPLICATION_OVERLAY
内部,多个悬浮窗口根据创建顺序或指定 Z-Order 排列。
- 在
5. 结论
- 主序 决定窗口的大层级,按照窗口类型排序,确保系统窗口优先于应用窗口。
- 子序 进一步细化相同类型窗口的排列顺序,通过窗口的
Z-Order
或Token
等属性动态调整。
主序和子序的协作机制,确保 Android 系统的窗口在复杂场景下能够按预期正确显示。主序用于描述窗口及其子窗口在所有窗口中的显示位置。子序则描述了一个子窗口在其兄弟窗口中的显示位置。主序越大,则窗口及其子窗口的显示位置相对于其他窗口的位置越靠前。子序越大,则子窗口相对于其兄弟窗口的位置越靠前。对于父窗口而言,其主序取决于其类型,其子序则保持为0。而子窗口的主序与其父窗口一样,子序则取决于其类型。
2.5 窗口的标志
-
// 当 Window 可见时允许锁屏
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
-
// Window 不能获得输入焦点,即不接受任何按键或按钮事件,例如该 Window 上 有 EditView,点击 EditView 是 不会弹出软键盘的
-
// Window 范围外的事件依旧为原窗口处理;例如点击该窗口外的view,依然会有响应。另外只要设置了此Flag,都将会启用
FLAG_NOT_TOUCH_MODAL
FLAG_NOT_FOCUSABLE = 0x00000008;
-
// 设置了该 Flag,将 Window 之外的按键事件发送给后面的 Window 处理, 而自己只会处理 Window 区域内的触摸事件
-
// Window 之外的 view 也是可以响应 touch 事件。
FLAG_NOT_TOUCH_MODAL = 0x00000020
;
- // 设置了该Flag,表示该 Window 将不会接受任何 touch 事件,例如点击该 Window 不会有响应,只会传给下面有聚焦的窗口。
FLAG_NOT_TOUCHABLE
;
-
// 只要 Window 可见时屏幕就会一直亮着
FLAG_KEEP_SCREEN_ON
-
// 允许 Window 超过屏幕之外
FLAG_LAYOUT_NO_LIMITS
-
// 当用户的脸贴近屏幕时(比如打电话),不会去响应此事件
FLAG_IGNORE_CHEEK_PRESSES
; -
// 窗口可以在锁屏的 Window 之上显示, 使用 Activity#setShowWhenLocked(boolean) 方法代替
FLAG_SHOW_WHEN_LOCKED = 0x00080000
;
3 WindowManager
3.1 添加Window
Activity#attach()方法之内PhoneWindow被创建,并同时创建一WindowManagerImpl负责维护PhoneWindow内的内容。
在Activity#onCreate()中调用setContentView()方法,这个方法内部创建一个DecorView实例作为PhoneWindow的内容。
WindowManagerImpl决定管理DecorView,并创建一个ViewRootImpl实例,将ViewRootImpl与View树进行关联,这样ViewRootImpl就可以指挥View树的具体工作。
3.2 activity与 PhoneWindow与DecorView关系
DecorView是FrameLayout的子类,它可以被认为是Android视图树的根节点视图
3.3 WindowManagerGlobal
3.4 ViewRootImpl
ViewRootImpl
是 Android 中一个非常重要的类,它是 View 树的根节点,负责将 View
层与 WindowManager
系统服务连接起来。ViewRootImpl
的职责是管理 View
的绘制、布局和事件分发,以及与窗口系统交互。
ViewRootImpl
是由 WindowManager
创建的。具体来说,它是在 WindowManagerImpl
调用 addView()
方法时,由 WindowManagerGlobal
内部负责创建的。
创建过程概述
-
Activity
启动时:- 每个
Activity
会创建一个Window
对象(通常是PhoneWindow
)。 PhoneWindow
的顶层视图是DecorView
,负责管理界面的 UI 树。- 当
WindowManager.addView()
被调用时,DecorView
会被添加到窗口系统中。
- 每个
-
WindowManager.addView()
方法:WindowManager
是一个接口,实际实现类是WindowManagerImpl
。WindowManagerImpl
的addView()
方法最终调用了WindowManagerGlobal.addView()
。
-
WindowManagerGlobal
创建ViewRootImpl
:WindowManagerGlobal.addView()
方法中,ViewRootImpl
实例被创建,并与DecorView
绑定。
1. ViewRootImpl
的定位
-
View
树的根节点:- 在 Android 的 UI 系统中,
View
树的根节点并不是直接由开发者创建的,而是由系统自动生成的ViewRootImpl
。 - 它是
DecorView
和窗口(WindowManager
)之间的桥梁。 DecorView
是Activity
的顶级视图,包含了标题栏、内容视图等。而ViewRootImpl
是实际管理DecorView
的类。
- 在 Android 的 UI 系统中,
-
连接
View
和WindowManager
:ViewRootImpl
通过WindowManagerGlobal
将视图树与WindowManager
进行绑定。- 每个
View
树的根节点都由一个ViewRootImpl
实例管理。
2. ViewRootImpl
的主要职责
(1)视图绘制流程
-
ViewRootImpl
负责整个View
树的绘制流程,包括以下三个主要阶段:-
测量(Measure) :
- 触发
ViewGroup
和其子视图的onMeasure
方法,计算每个视图的大小。
- 触发
-
布局(Layout) :
- 确定每个
View
的位置,调用onLayout
方法。
- 确定每个
-
绘制(Draw) :
- 调用每个
View
的onDraw
方法,将视图渲染到屏幕上。
- 调用每个
-
-
这些流程是由
ViewRootImpl
的performTraversals
方法触发的。
(2)事件分发
-
ViewRootImpl
负责将用户输入事件(如触摸、按键等)从系统事件队列传递到View
树。 -
事件分发流程:
ViewRootImpl
从InputDispatcher
获取事件。- 调用
View
树根节点的dispatchTouchEvent
或dispatchKeyEvent
方法,将事件分发给视图。
DecorView虽然是ViewGroup,但它并不会直接分发给它的child,也不会传递给它的父View,而是先分发给Activity,为什么要这么做呢?
我们可想DecorView 拿到事件后,若直接向下分发,那就没Activity的事了,但Activity也想成为事件分发的一环,并还想作为优先级较高的部分。所以就可以通过这种方式,绕了一圈又回到DecorView并再往下分发。DecorView在这里承担两个职责:
-
在接收到输入事件时,它不同于普通View,分发给子view,而是会先将事件分发给上层的Activity
-
接收到上层Activity分发下的事件后,又会变成普通View,进行ViewGroup的事件分发
(3)管理窗口的生命周期
ViewRootImpl
通过WindowManager
来管理窗口(Window)的添加、删除和更新。- 它接收窗口的各种状态变化(如大小调整、焦点变化),并通知
View
树更新。
(4)消息处理
-
ViewRootImpl
使用Handler
来处理与 UI 相关的消息。 -
常见的消息:
- 绘制视图(
MSG_DO_TRAVERSAL
) - 处理输入事件(
MSG_PROCESS_INPUT_EVENTS
) - 窗口大小调整(
MSG_RESIZED
)
- 绘制视图(
3. ViewRootImpl
的核心方法
(1)performTraversals
-
这是
ViewRootImpl
中最重要的方法之一,用于完成视图的测量、布局和绘制流程。 -
具体流程:
- 调用
View.measure()
,计算视图的大小。 - 调用
View.layout()
,确定视图的位置。 - 调用
View.draw()
,将视图绘制到屏幕上。
- 调用
(2)dispatchInputEvent
-
用于处理输入事件,如触摸和按键事件。
-
流程:
- 将事件传递给
DecorView
。 - 通过
ViewGroup
的事件分发机制,将事件传递到目标View
。
- 将事件传递给
(3)scheduleTraversals
- 触发一次完整的视图刷新流程。
- 当视图树发生变化(如视图大小、位置变化或需要重绘)时调用。
(4)setView
- 负责将一个
DecorView
与窗口系统绑定。 - 在
Activity
启动时,WindowManager.addView()
方法会调用此方法,将DecorView
添加到窗口中。
4. ViewRootImpl
的生命周期
-
初始化:
- 当
WindowManager.addView()
被调用时,ViewRootImpl
会被创建,并绑定一个DecorView
。
- 当
-
运行时管理:
- 在应用运行过程中,
ViewRootImpl
负责处理视图树的绘制、布局、事件分发等。
- 在应用运行过程中,
-
销毁:
- 当
WindowManager.removeView()
被调用时,ViewRootImpl
会将视图树从窗口中移除,并释放相关资源。
- 当
5. ViewRootImpl
的作用与意义
-
连接桥梁:
- 作为
View
树和系统窗口的连接桥梁,它将用户的操作与应用的 UI 渲染有效结合。
- 作为
-
高效管理 UI:
- 通过消息队列、输入分发、绘制流程等,
ViewRootImpl
高效地管理了 UI 的更新和响应。
- 通过消息队列、输入分发、绘制流程等,
-
优化系统性能:
- 它通过分帧绘制、事件优化等机制,确保了 UI 的流畅性。
6. ViewRootImpl
的典型调用流程
以下是 ViewRootImpl
在一个 Activity
启动过程中的调用流程:
-
Activity
创建窗口:- 在
Activity
启动时,Window
对象被创建。 Window
的顶级视图是DecorView
。
- 在
-
WindowManager
添加视图:WindowManager.addView()
被调用。- 系统会创建一个
ViewRootImpl
实例,并调用其setView()
方法,将DecorView
与ViewRootImpl
绑定。
-
触发视图绘制:
ViewRootImpl
的performTraversals
方法被调用,完成视图的测量、布局和绘制流程。
-
事件分发:
- 用户的触摸或按键事件通过
InputDispatcher
传递给ViewRootImpl
。 - 事件通过
ViewRootImpl.dispatchInputEvent()
方法分发到DecorView
,并最终传递到目标View
。
- 用户的触摸或按键事件通过
4 UI刷新的流程
1. 刷新流程概述
Android UI 刷新是一个复杂的过程,主要由以下步骤组成:
- 触发刷新请求:应用逻辑调用
invalidate()
或requestLayout()
。 - 主线程任务调度:通过
ViewRootImpl
的scheduleTraversals()
,将刷新任务发送到消息队列。 - 执行绘制流程:
ViewRootImpl
执行视图树的三大流程:measure
(测量)、layout
(布局)、draw
(绘制)。 - 与硬件加速交互:通过
Choreographer
控制帧同步和绘制时机。 - 渲染到屏幕:最终将 UI 数据交给 GPU 进行绘制,并通过 SurfaceFlinger 显示在屏幕上。
2. 刷新触发机制
刷新流程通常由以下两种情况触发:
-
视图内容变化:
- 调用
View.invalidate()
:只触发重绘,不涉及视图树的重新布局。 - 调用
View.requestLayout()
:视图大小或位置发生变化,触发布局和绘制。
- 调用
-
系统事件:
- 如屏幕旋转、窗口大小改变或 Activity 生命周期回调(如
onResume
)等。
- 如屏幕旋转、窗口大小改变或 Activity 生命周期回调(如
3. 主线程任务调度
-
View.invalidate()
或requestLayout()
invalidate()
会标记当前视图为需要重绘。requestLayout()
会标记视图树为需要重新布局,并触发整个视图树的重新绘制。
-
ViewRootImpl.scheduleTraversals()
invalidate()
或requestLayout()
最终都会调用ViewRootImpl.scheduleTraversals()
。- 它会将一个刷新任务(
doTraversal
)投递到主线程的消息队列中。
-
通过
Looper
和Handler
调度ViewRootImpl
使用主线程的Handler
将刷新任务发送到MessageQueue
。- 当主线程空闲时,处理该刷新任务。
4. 绘制流程
核心绘制流程由 ViewRootImpl.performTraversals()
方法驱动,依次完成以下三个阶段:
(1)测量阶段(Measure)
- 调用
View.measure()
,从根视图开始递归测量每个子视图的尺寸。 - 每个视图通过其
onMeasure()
方法决定自己的大小。 - 结果存储在
MeasureSpec
中。
(2)布局阶段(Layout)
- 调用
View.layout()
,从根视图开始递归为每个子视图设置具体的位置。 - 每个视图通过其
onLayout()
方法决定子视图的位置。
(3)绘制阶段(Draw)
-
调用
View.draw()
,从根视图开始递归绘制视图树。 -
绘制过程依次调用:
drawBackground()
:绘制背景。onDraw()
:绘制视图内容。dispatchDraw()
:绘制子视图。drawForeground()
:绘制前景。
5. 帧同步与硬件加速
-
Choreographer
Choreographer
是 Android 控制帧同步的核心组件。- 它会根据屏幕刷新频率(通常是 60 FPS,即每 16ms 一帧)调用
doFrame()
方法,确保绘制过程与屏幕刷新节奏一致。
-
硬件加速
- 绘制过程通常使用 GPU 硬件加速,通过 OpenGL 将视图内容渲染到缓冲区。
- Android 使用
DisplayList
(显示列表)记录视图的绘制命令,并通过RenderThread
提交给 GPU。
6. 渲染到屏幕
-
Surface 和 SurfaceFlinger
ViewRootImpl
最终将绘制内容提交到Surface
。Surface
是视图内容在系统中的缓冲区,属于SurfaceControl
管理的图层。
-
合成与显示
- 系统中的
SurfaceFlinger
合成所有应用窗口的内容,并通过硬件 Composer 显示到屏幕上。
- 系统中的
7. 完整调用链
代码触发流程
java
复制代码
View.invalidate() → ViewParent.invalidateChild() → ViewRootImpl.invalidateChild()
→ scheduleTraversals() → doTraversal()
→ performTraversals() → measure() → layout() → draw()
核心方法调用链
invalidate()
或requestLayout()
标记视图树需要更新。scheduleTraversals()
提交刷新任务到主线程消息队列。doTraversal()
开始视图树的measure
、layout
和draw
阶段。- 调用
Choreographer.postFrameCallback()
注册下一帧刷新。 - 最终绘制内容提交到
Surface
,通过SurfaceFlinger
合成显示。
8 面试问题
-
- 连续两次setTextView到底会触发几次UI重绘呢?
等到VSYNC到来后,会移除同步栅栏,并率先开始执行当前帧的处理,调用逻辑如下
VSYNC要客户端主动申请,才会有有VSYNC到来才会刷新,UI没更改,不会请求VSYNC也就不会刷新UI局部,重绘其实只会去重绘带刷新的View
-
- 为什么Android APP的帧率一般是60FPS?
1. 硬件刷新率的限制
-
屏幕刷新率:
- 大多数 Android 设备的屏幕刷新率是 60Hz,即屏幕每秒刷新60次。
- 应用的绘制频率与屏幕刷新率同步,以避免出现画面撕裂(tearing)或卡顿现象。
- 如果帧率超过屏幕刷新率,额外的帧也无法在屏幕上显示,因此没必要绘制更多帧。
2. 帧时间计算(16ms规则)
-
每帧时间限制:
- 60FPS意味着每帧的显示时间是 1秒 ÷ 60 = 16.67ms。
- Android 应用需要在这 16ms 内完成所有操作(包括布局计算、绘制、动画、输入事件处理等)。
- 超过 16ms,就会导致掉帧(frame drop),肉眼会察觉到卡顿。
-
理论帧率公式:
- 帧率(FPS) = 1 ÷ 每帧所需时间。
- 如果绘制一帧的时间为 33ms,则帧率降为 30FPS。
3. 人眼视觉感知
-
视觉流畅性的需求:
- 人眼对动态画面的流畅感要求一般在 24-30FPS 以上。
- 60FPS 被认为是流畅的临界值,足够应对普通应用场景。
-
更高帧率的平滑效果:
- 高帧率(如120FPS)在游戏和交互性强的场景下表现更好,但会显著增加设备功耗和发热问题。
- 对于普通移动应用来说,60FPS 已经是性能和功耗的最佳平衡点。
4. Vsync 同步机制
-
什么是 Vsync?
- Android 使用 Vsync(Vertical Synchronization)信号来同步屏幕刷新和应用绘制。
- Vsync 每16.67ms发出一次信号,通知系统准备好下一帧内容。
-
Choreographer 的帧调度:
- Android 的
Choreographer
组件通过监听 Vsync 信号,调用doFrame()
方法完成绘制任务。 - 应用的绘制时间点与屏幕刷新周期保持一致,从而避免画面撕裂或不一致。
- Android 的
5 SurfaceFlinger
SurfaceFlinger 第一定律 是指 SurfaceFlinger 合成所有应用窗口内容时的一个基本规则:
"屏幕上的每个像素只能由一个图层提供。"
含义详解
-
SurfaceFlinger 是 Android 中负责图像合成与显示的系统服务。它将来自不同应用或窗口的图层(Layer)合成到一块缓冲区(FrameBuffer)上,并最终通过硬件 Composer 显示在屏幕上。
-
第一定律 的核心思想是:在任何时刻,屏幕上每个像素点的显示内容都由某个图层独占。
- 不允许多个图层的内容同时覆盖到同一个像素点。
- 每个像素点的最终颜色值只能来源于一个图层。
SF是整个Android系统渲染的核心进程。所有应用的渲染逻辑最终都会来到SF中进行处理,最终会把处理后的图像数据交给CPU或者GPU进行绘制。
在每一个应用中都以Surface作为一个图元传递单元,向SF这个服务端传递图元数据。
作用与设计目的
-
避免重复渲染:
- 如果同一个像素被多个图层同时覆盖,系统需要反复计算,导致性能下降。
- 第一定律确保每个像素只被计算一次,提高了渲染效率。
-
明确显示逻辑:
- 确定前景、背景层级(Z-Order)和覆盖关系,确保显示逻辑清晰。
- 当多个图层存在重叠时,Z-Order 决定优先级,最上层的图层内容会显示。
-
优化硬件 Composer:
- 硬件 Composer 是 SurfaceFlinger 用于图像合成的关键组件,第一定律使其无需处理复杂的图层交叠问题。
应用场景
-
窗口系统合成:
- 当多个应用窗口(如 Activity、对话框、悬浮窗)同时存在时,SurfaceFlinger 按 Z-Order 合成这些窗口,只显示最上层内容。
-
游戏与多媒体播放:
- 游戏场景中,UI 图层、渲染内容图层、特效图层等按顺序合成,避免画面错乱。
- 视频播放时,播放器的 Surface 会优先显示。
-
过渡动画:
- 在应用切换时,通过设置图层的透明度和层级,完成动画效果,而不会破坏显示的完整性。
第一定律的实现
SF是以生产者以及消费者为核心设计思想,把每一个应用进程作为生产者生产图元保存到SF的图元队列中,SF则作为消费者依照一定的规则把生产者存放到SF中的队列一一处理。
-
图层管理:
- SurfaceFlinger 管理每个图层(Layer)的 Z-Order。
- 根据 Z-Order 决定图层的显示优先级,确保屏幕每个像素的显示来源是最高优先级的图层。
-
合成操作:
- SurfaceFlinger 收集所有需要显示的图层数据(通常为 Surface 提供的缓冲区)。
- 对重叠区域,按照 Z-Order 选择最高优先级的图层内容。
-
透明度处理:
- 如果图层具有透明属性(Alpha 值),则对背景进行混合(Blending)操作,计算出最终显示的颜色值。