本文講的是Android視圖的繪製的三大流程,視圖的工做流程主要是指測量,佈局,繪製這三大流程,即測量,佈局和繪製,其中測量肯定查看的測量寬高,佈局根據測量的寬高肯定視圖在其父視圖中的四個頂點的位置,而平局則將查看繪製到屏幕上,這樣經過一個ViewGroup的遞歸遍歷,一個景觀樹就展示在屏幕上了。說的簡單,下面帶你們一步一步從源碼中分析:java
安卓的視圖是樹形結構的:微信
基本概念佈局
在介紹視圖的三大流程以前,咱們必須先介紹一些基本的概念,才能更好地理解這整個過程。this
窗口的概念orm
窗口表示的是一個窗口的概念,它是站在WindowManagerService角度上的一個抽象的概念,安卓中全部的視圖都是經過窗口來呈現的,不論是活動,對話仍是麪包,只要有瀏覽的地方就必定有窗口。對象
這裏須要注意的是,這個抽象的窗口概念和PhoneWindow這個類並非同一個東西,PhoneWindow表示的是手機屏幕的抽象,它充當活動和DecorView之間的媒介,就算沒有PhoneWindow也是能夠展現查看的。blog
拋開一切,僅站在WindowManagerService的角度上,安卓的界面就是由一個個窗口層疊展示的,而窗戶又是一個抽象的概念,它並非實際存在的,它是以景觀的形式存在,這個視圖就是DecorView。繼承
關於窗口這方面的內容,咱們這裏先了解一個大概遞歸
DecorView的概念事件
DecorView是整個窗口界面的最頂層視圖,視圖的測量,佈局,繪製,事件分發都是由DecorView往下遍歷這個景觀樹.DecorView做爲頂級景觀,通常狀況下它內部會包含一個豎直方向的LinearLayout中,在這個的LinearLayout裏面有上下兩個部分(具體狀況和的Android的版本及主題有關),上面是【標題欄】,下面是【內容欄】。在活動中咱們經過的setContentView所設置的佈局文件其實就是被加載到【內容欄】中的,而內容欄的ID是內容,所以指定佈局的方法叫setContent()。
的ViewRoot的概念
的ViewRoot對應於ViewRootImpl類,它是鏈接的WindowManager和DecorView的紐帶,查看的三大流程均是經過的ViewRoot來完成的。在ActivityThread中,當活動對象被建立完以後,會講DecorView添加到窗口中,同時會建立對應的ViewRootImpl,並將ViewRootImpl和DecorView創建關聯,並保存到WindowManagerGlobal對象中。
Java的
查看的繪製流程是從的ViewRoot的performTraversals方法開始的,它通過測量,佈局和繪製三個過程才能最終將一個視圖繪製出來,大體流程以下圖:
測量測量
爲了更好地理解查看的測量過程,咱們還須要理解MeasureSpec,它是搜索的一個內部類,它表示對查看的測量規格.MeasureSpec表明一個32位INT值,高2位表明SpecMode(測量模式),低30位表明SpecSize(測量大小),咱們能夠看看它的具體實現:
Java的
MeasureSpec經過將SpecMode和SpecSize打包成一個INT值來避免過多的對象內存分配,並提供了打包和解包的方法。
SpecMode有三種類型,每一類都表示特殊的含義:
UNSPECIFIED
父容器不對視圖有任何限制,要多大就給多大,這種狀況通常用於系統內部,表示一種測量的狀態;
究竟
父容器已經檢測出查看所需的精確大小,這個時候搜索的最終打消就是SpecSize所指定的值。它對應於的LayoutParams中的match_parent和具體數值這兩種模式。
最多
父容器指定了一個可用大小即SpecSize,查看的大小不能大於這個值,具體是什麼值要看不一樣觀的具體實現。它對應於的LayoutParams中WRAP_CONTENT。
查看的MeasureSpec是由父容器的MeasureSpec和本身的的LayoutParams決定的,可是對於DecorView來講有點不一樣,由於它沒有父類。在ViewRootImpl中的measureHierarchy方法中有以下一段代碼展現了DecorView的MeasureSpec的建立過程,其中desiredWindowWidth和desireWindowHeight是屏幕的尺寸大小:
ViewGroup中的措施
Java的
再看看getRootMeasureSpec方法:
Java的
經過以上代碼,DecorView的MeasureSpec的產生過程就很明確了,由於DecorView是FrameLyaout的子類,屬於ViewGroup中,對於ViewGroup中來講,除了完成本身的測量過程外,還會遍歷去調用全部子元素的測量方法,各個子元素再遞歸去執行這個過程。和查看不一樣的是,一個ViewGroup是一個抽象類,他沒有重寫查看的onMeasure方法,這裏很好理解,由於每一個具體的ViewGroup中實現類的功能是不一樣的,如何測量應該讓它本身決定,好比LinearLayout中和RelativeLayout的。
所以在具體的一個ViewGroup中須要遍歷去測量子查看,這裏咱們看看一個ViewGroup中提供的測量子視圖的measureChildWithMargins方法:
Java的
上述方法會對子元素進行測量,在調用子元素的測量方法以前會先經過getChildMeasureSpec方法來獲得子元素的MeasureSpec。從代碼上看,子元素的MeasureSpec的建立與父容器的MeasureSpec和自己的的LayoutParams有關,此外和查看的保證金和父類的填充有關,如今看看getChildMeasureSpec的具體實現:
Java的
上述代碼根據父類的MeasureSpec和自身的的LayoutParams建立子元素的MeasureSpec,具體過程同窗們自行分析,最終的建立規則以下表:
ViewGroup中在遍歷完子視圖後,須要根據子元素的測量結果來決定本身最終的測量大小,並調用setMeasuredDimension方法保存測量寬高值。
Java的
這裏調用了resolveSizeAndState來肯定最終的大小,主要是保證測量的大小不能超過父容器的最大剩餘空間maxWidth,這裏咱們看看它裏面的實現:
Java的
關於具體的ViewGroup的onMeasure過程這裏不作分析,因爲每種佈局的測量方式不同,不可能逐個分析,但在它們的onMeasure裏面的步驟是有必定規律的:
1.根據各自的測量規則遍歷兒童元素,調用getChildMeasureSpec方法獲得孩子的measureSpec;
2.調用兒童的度量方法;
3.調用setMeasuredDimension肯定最終的大小。
查看的措施
查看的測量過程由其測量方法來完成,測量方法是一個最終的類型的方法,這意味着子類不能重寫此方法,在景觀的措施方法裏面會去調用onMeasure方法,咱們這裏只要看onMeasure的實現便可,以下:
Java的
代碼很簡單,咱們繼續看看getDefaultSize方法的實現:
Java的
從上述代碼能夠得出,景觀的寬/高由specSize決定,直接繼承視圖的自定義控件須要重寫onMeasure方法並設置WRAP_CONTENT時的自身大小,不然在佈局中使用WRAP_CONTENT就至關於使用match_parent。
上述就是查看的量度大體過程,在測量完成以後,經過getMeasuredWidth /高度方法就能夠得到測量後的寬高,這個寬高通常狀況下就等於查看的最終寬高了,由於搜索的佈局佈局的時候就是根據measureWidth /高度來設置寬高的,除非在佈局中修改了測量值。
佈局佈局
佈局的做用是一個ViewGroup用來肯定子元素的位置,當ViewGroup中的位置被肯定後,它在onLayout中會遍歷全部的子元素並調用其佈局方法。簡單的來講就是,佈局方法肯定視圖自己的位置,而onLayout方法則會肯定全部子元素的位置。
先看看查看的佈局方法:
因微信字數限制,請點擊原文連接查看完整內容
總結
到這裏,查看的措施,佈局,繪製三大流程就說完了,這裏作一下總結: