Android UI的绘制流程
ViewRootImpl类
ViewRootImpl 类是连接 WindowManager 和 DecorView 的纽带。ActivityThread 中当 activity 对象被创建好后,会将 DecorView 加入到 Window中,同时完成 ViewRootImpl 的创建并建立和 DecorView 的联系。
root = new ViewRootImpl(view.getContext(), display);
root.setView(view, wparams, panelParentView);
View的绘制是由Android系统的ViewRootImpl类中的performTraversals()方法触发的。通过ViewRootImpl类的performTraversals()方法,系统会依次调用View的measure()、layout()和draw()方法,完成View的绘制流程。
代码省略如下:
private void performTraversals() {
// Ask host how big it wants to be
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
performLayout(lp, mWidth, mHeight);
if (!performDraw() && mActiveSurfaceSyncGroup != null) {
mActiveSurfaceSyncGroup.markSyncReady();
}
}
测量流程
在performMeasure()方法中,通过遍历View树,调用每个View的measure()方法来进行测量操作。
布局流程
在performLayout()方法中,通过遍历View树,调用每个View的layout()方法来进行布局操作。
绘制流程
在performDraw()方法中,首先创建一个Canvas对象,并清空画布。然后,通过遍历View树,调用每个View的draw()方法来执行实际的绘制操作。最后,解锁画布并提交绘制结果。最开始生成的画布会一直传给每一个子View来绘制。
对于绘制这里说一句:
View的绘制过程遵循如下几步;
①绘制背景 background.draw(canvas)
②绘制自己(onDraw)
③绘制Children(dispatchDraw)
④绘制滚动条和前景色(onDrawForeground)
⑤绘制高亮线(drawDefaultFocusHighlight)
public void draw(@NonNull Canvas canvas) {
final int privateFlags = mPrivateFlags;
mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
/*
* Draw traversal performs several drawing steps which must be executed
* in the appropriate order:
*
* 1. Draw the background
* 2. If necessary, save the canvas' layers to prepare for fading
* 3. Draw view's content
* 4. Draw children
* 5. If necessary, draw the fading edges and restore layers
* 6. Draw decorations (scrollbars for instance)
* 7. If necessary, draw the default focus highlight
*/
// Step 1, draw the background, if needed
int saveCount;
drawBackground(canvas);
// skip step 2 & 5 if possible (common case)
final int viewFlags = mViewFlags;
boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
if (!verticalEdges && !horizontalEdges) {
// Step 3, draw the content
onDraw(canvas);
// Step 4, draw the children
dispatchDraw(canvas);
drawAutofilledHighlight(canvas);
// Overlay is part of the content and draws beneath Foreground
if (mOverlay != null && !mOverlay.isEmpty()) {
mOverlay.getOverlayView().dispatchDraw(canvas);
}
// Step 6, draw decorations (foreground, scrollbars)
onDrawForeground(canvas);
// Step 7, draw the default focus highlight
drawDefaultFocusHighlight(canvas);
if (isShowingLayoutBounds()) {
debugDrawFocus(canvas);
}
// we're done...
return;
}