View繪製(一) performTraversals
View的繪製是一個遞迴的過程,父View繪製自己和子View,然後子view繪製自己和自己的子View。
我們知道遞迴的一般數學表達是A1=T,An=f(An-1),那麼與之對應,View繪製的A1和函式f()又是什麼呢?
答案 :View繪製的A1是DecorView,它是View繪製的起始節點,View繪製的f()函式是measure,layout,draw三大過程,通過遞迴呼叫這三個方法完成View的繪製。
在介紹View的繪製過程之前,先介紹幾點關於View的相關概念,方便大家理解。
一、View相關概念
PhoneWindow:繼承自Window類,負責管理介面顯示以及事件響應,每個Activity 介面都包含一個PhoneWindow物件,它是Activity和整個View系統互動的介面。
DecorView:是PhoneWindow中的起始節點View,繼承自View類,是作為整個檢視容器來使用的,主要負責設定視窗屬性。
ViewRoot:在系統啟動一個Activty元件的同時將其建立,類似於MVC模型中的Controller,負責管理、佈局和渲染視窗UI等事務。
二、View繪製開始
系統啟動一個Activity的同時建立一個ViewRoot例項。
Activity 在attach階段生成一個PhoneWindow物件,它包含一個DecorView物件。
在Activity執行onCreate中的setContentView之後,將讀入的view載入進入第一張圖的ContentViews區域。
載入完畢後觸發ViewRoot中的scheduleTraversals非同步函式,從而進入ViewRoot的performTraversals函式,View的繪製從這裡開始。
三、performTraversals
ViewRoot中的performTraversals方法以DecorView為父容器(ViewGroup)開始自上而下的View工作流程。
View的工作流程主要是指measure、layout、draw這三大流程,即測量、佈局和繪製,其中measure確定View的測量寬和高,layout確定View的最終寬/高和四個頂點位置,而draw則將View繪製到螢幕上。
關於measure,layout,draw的具體內容可以看後面的文章,這裡不用多在意。這個函式的執行過程主要是根據之前設定的狀態,判斷是否重新計算檢視大小(measure)、是否重新放置檢視的位置(layout)、以及是否重繪 (draw),其核心也就是通過判斷來選擇順序執行這三個方法中的哪個。
private void performTraversals() {
//1 處理mAttachInfo的初始化,並根據resize、visibility改變的情況,給相應的變數賦值。
final View host = mView;//這裡的mView即DecorView
final View.AttachInfo attachInfo = mAttachInfo;
final int viewVisibility = getHostVisibility();
boolean viewVisibilityChanged = mViewVisibility != viewVisibility
|| mNewSurfaceNeeded;
float appScale = mAttachInfo.mApplicationScale;
WindowManager.LayoutParams params = null;
if (mWindowAttributesChanged) {
mWindowAttributesChanged = false;
surfaceChanged = true;
params = lp;
}
Rect frame = mWinFrame;
if (mFirst) {
// For the very first time, tell the view hierarchy that it
// is attached to the window. Note that at this point the surface
// object is not initialized to its backing store, but soon it
// will be (assuming the window is visible).
attachInfo.mSurface = mSurface;
attachInfo.mUse32BitDrawingCache = PixelFormat.formatHasAlpha(lp.format) ||
lp.format == PixelFormat.RGBX_8888;
attachInfo.mHasWindowFocus = false;
attachInfo.mWindowVisibility = viewVisibility;
......
}
//2 如果mLayoutRequested判斷為true,那麼說明需要重新layout,不過在此之前那必須重新measure。
if (mLayoutRequested) {
// Execute enqueued actions on every layout in case a view that was detached
// enqueued an action after being detached
getRunQueue().executeActions(attachInfo.mHandler);
if (mFirst) {
......
}
}
//3 判斷是否有子檢視的屬性發生變化,ViewRoot需要獲取這些變化。
if (attachInfo.mRecomputeGlobalAttributes) {
......
}
if (mFirst || attachInfo.mViewVisibilityChanged) {
......
}
//4 根據上面得到的變數數值,確定我們的view需要多大尺寸才能裝下。於是就得measure了,有viewgroup的weight屬性還得再做些處理
// Ask host how big it wants to be
host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
mLayoutRequested = true;
}
}
//5 measure完畢,接下來可以layout了。
final boolean didLayout = mLayoutRequested;
boolean triggerGlobalLayoutListener = didLayout
|| attachInfo.mRecomputeGlobalAttributes;
if (didLayout) {
host.layout(0, 0, host.mMeasuredWidth, host.mMeasuredHeight);
}
//6 如果mFirst為true,那麼會進行view獲取焦點的動作。
if (mFirst) {
mRealFocusedView = mView.findFocus();
}
boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw();
//7 終於,來到最後一步,前面的工作可以說都是鋪墊,都是為了draw而準備的。
if (!cancelDraw && !newSurface) {
mFullRedrawNeeded = false;
draw(fullRedrawNeeded)
}
相關文章
- View的繪製二:View的繪製流程View
- View繪製——畫多大?View
- View繪製——畫在哪?View
- View 繪製流程分析View
- View 的繪製過程View
- View繪製——怎麼畫?View
- Flutter 自定義繪製 ViewFlutterView
- Android View繪製流程AndroidView
- 每日一問:簡述 View 的繪製流程View
- View繪製流程原始碼分析View原始碼
- View的繪製三:UI繪製的三大步驟ViewUI
- Android View繪製原理:繪製流程排程、測算等AndroidView
- View的繪製一:View是如何被新增到螢幕視窗上的View
- Android View的繪製過程AndroidView
- 初·Android View的繪製流程AndroidView
- Android 中 View 繪製流程分析AndroidView
- View 繪製體系知識梳理(4) 繪製過程之 Layout 詳解View
- View 繪製體系知識梳理(5) 繪製過程之 Draw 詳解View
- View的繪製-measure流程詳解View
- Android進階(五)View繪製流程AndroidView
- 初探Android的View繪製過程AndroidView
- Anroid自定義View-繪製圓環View
- Android View 繪製流程(Draw) 完全解析AndroidView
- Android View繪製13問13答AndroidView
- Android View 原始碼解析(三) – View的繪製過程AndroidView原始碼
- View繪製01-Android渲染系統中的ViewViewAndroid
- Android自定義View之(一)View繪製流程詳解——向原始碼要答案AndroidView原始碼
- View 繪製體系知識梳理(3) 繪製流程之 Measure 詳解View
- Android繪製View的過程研究——計算View的大小AndroidView
- Android原始碼分析之View繪製流程Android原始碼View
- Android View繪製原始碼分析 MeasureAndroidView原始碼
- 自定義View的繪製流程基礎分析View
- 【Android原始碼】View的繪製流程分析Android原始碼View
- 探究 Android View 繪製流程,Activity 的 View 如何展示到螢幕AndroidView
- 使用自定義 View 繪製一個懸浮式可拖拽按鈕View
- View 繪製體系知識梳理(6) 繪製過程之 requestLayout 和 invalidate 詳解View
- flutter 自定義view 繪製曲線統計圖FlutterView
- 探究Android View 繪製流程,Canvas 的由來AndroidViewCanvas