文章目录
- [Android 绘制流程源码分析](#Android 绘制流程源码分析)
Android 绘制流程源码分析
概述
View 的绘制流程是 UI 渲染的核心机制,主要包括三个阶段:
- measure 测量:确定 View 以及子 View 的尺寸。
- layout 布局:确定 View 以及子 View 在父容器中的坐标。
- draw 绘制:将 View 绘制到屏幕上。
由 ViewRootImpl 驱动整个流程。
requestLayout() 和 invalidate() 最终也会通过 ViewRootImpl 触发完整或部分流程。
流程
ViewRootImpl.performTraversals()
↓
performMeasure() → View.measure() → onMeasure()
↓
performLayout() → View.layout() → onLayout()
↓
performDraw() → View.draw() → onDraw()
源码分析
ViewRootImpl.performTraversals()
java
private void performTraversals() {
// ViewRootImpl的测量规格
childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width, lp.privateFlags);
childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height, lp.privateFlags);
// 测量阶段
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
if (didLayout) {
// 布局阶段
performLayout(lp, mWidth, mHeight);
}
// 绘制阶段
performDraw(mActiveSurfaceSyncGroup)
}
ViewRootImpl.performMeasure()
java
private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
if (mView == null) {
return;
}
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
try {
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
mMeasuredWidth = mView.getMeasuredWidth();
mMeasuredHeight = mView.getMeasuredHeight();
mViewMeasureDeferred = false;
}
View.measure()
java
// final方法,不能被重写
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
// 实际测量逻辑
onMeasure(widthMeasureSpec, heightMeasureSpec);
}
FrameLayout.onMeasure()
java
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 获取子View数量
int count = getChildCount();
int maxHeight = 0;
int maxWidth = 0;
int childState = 0;
// 遍历子View
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (mMeasureAllChildren || child.getVisibility() != GONE) {
// 测量子View
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
// ...
}
}
// 根据子View尺寸和自身规则,计算资金的尺寸
setMeasuredDimension(
resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
resolveSizeAndState(maxHeight, heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT)
);
}
ViewRootImpl.performLayout()
java
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
int desiredWindowHeight) {
// host既DecorView
host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
}
View.layout()
java
public void layout(int l, int t, int r, int b) {
// 设置自身位置
boolean changed = setFrame(l, t, r, b);
// 位置/尺寸发生变化,重写调用onLayout
if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
// 由ViewGroup处理,实际布局逻辑
onLayout(changed, l, t, r, b);
}
}
LinearLayout.onLayout()
java
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (mOrientation == VERTICAL) {
layoutVertical(l, t, r, b);
} else {
layoutHorizontal(l, t, r, b);
}
}
java
void layoutVertical(int left, int top, int right, int bottom) {
// 遍历子View
for (int i = 0; i < count; i++) {
final View child = getVirtualChildAt(i);
if (child == null) {
childTop += measureNullChild(i);
} else if (child.getVisibility() != GONE) {
// 测量子View宽高
final int childWidth = child.getMeasuredWidth();
final int childHeight = child.getMeasuredHeight();
final LinearLayout.LayoutParams lp =
(LinearLayout.LayoutParams) child.getLayoutParams();
int gravity = lp.gravity;
if (gravity < 0) {
gravity = minorGravity;
}
final int layoutDirection = getLayoutDirection();
final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.CENTER_HORIZONTAL:
childLeft = paddingLeft + ((childSpace - childWidth) / 2)
+ lp.leftMargin - lp.rightMargin;
break;
case Gravity.RIGHT:
childLeft = childRight - childWidth - lp.rightMargin;
break;
case Gravity.LEFT:
default:
childLeft = paddingLeft + lp.leftMargin;
break;
}
if (hasDividerBeforeChildAt(i)) {
childTop += mDividerHeight;
}
childTop += lp.topMargin;
// 计算子View坐标,调用layout()
setChildFrame(child, childLeft, childTop + getLocationOffset(child),
childWidth, childHeight);
childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);
i += getChildrenSkipCount(child, i);
}
}
}
private void setChildFrame(View child, int left, int top, int width, int height) {
child.layout(left, top, left + width, top + height);
}
ViewRootImpl.performDraw()
java
private boolean performDraw(@Nullable SurfaceSyncGroup surfaceSyncGroup) {
// 最终调用DecorView.draw()
mView.draw(canvas)
}
View.draw()
java
public void draw(@NonNull Canvas canvas) {
// 绘制背景
drawBackground(canvas);
// 实际绘制逻辑
onDraw(canvas);
// 绘制子View
dispatchDraw(canvas);
drawAutofilledHighlight(canvas);
// 绘制前景
onDrawForeground(canvas);
// 默认焦点高亮
drawDefaultFocusHighlight(canvas);
}